7

Tengo un problema actualizando una clave externa en una entidad Entity Framework. Estoy usando entidades de seguimiento propio y tengo una entidad con algunas relaciones donde la clave externa también está presente como una propiedad (una de las nuevas características de EF4). La clave (un entero) está marcada como Nullable y modo Concurrencia corregido.¿Se permiten claves foráneas con nulos en Entity Framework 4?

Específicamente tengo una entidad de alarma con una relación de muchos a 0..1 con un usuario confirmante. (un usuario puede confirmar varias alarmas, pero una alarma puede ser confirmada solo por cero o por un usuario).

Las definiciones de entidades (simplificadas):

Alarm properties 
Id  Int32 non-nullable identity entity key 
UserId Int32 nullable concurrency mode fixed 
Alarm navigation properties 
User 0..1 multiplicity 

User properties 
Id  Int32 non-nullable identity entity key 
Name String non-nullable 

En mi entidad de seguimiento auto la confirmación de ID de usuario es como anulable justo lo que esperábamos auto-generado, sin embargo si le asigno un usuario a una alarma ya persistente y ejecutar ApplyChanges, la extensión de contexto de auto-seguimiento intenta establecer el valor original (nulo) en el contexto EF (en SetValue en las extensiones de contexto), pero se salta silenciosamente porque el ClrEquivalentType del EdmType es un Int32 que no admite nulos.

código de extensión generada automáticamente:

private static void SetValue(this OriginalValueRecord record, EdmProperty edmProperty, object value) 
    { 
     if (value == null) 
     { 
      Type entityClrType = ((PrimitiveType)edmProperty.TypeUsage.EdmType).ClrEquivalentType; 
      if (entityClrType.IsValueType && 
       !(entityClrType.IsGenericType && typeof(Nullable<>) == entityClrType.GetGenericTypeDefinition())) 
      { 
       // Skip setting null original values on non-nullable CLR types because the ObjectStateEntry won't allow this 
       return; 
      } 
     } 

     int ordinal = record.GetOrdinal(edmProperty.Name); 
     record.SetValue(ordinal, value); 
    } 

Cuando el EF tarde intenta actualizar mi alarma me sale un OptimisticConcurrencyException porque construye una cláusula WHERE en la instrucción UPDATE donde se utiliza 0 (cero) que el original el valor de la clave externa del usuario en lugar del correcto "es nulo". (La cláusula WHERE es parte del mecanismo de simultaneidad optimista EF, donde los valores originales de las propiedades marcadas con el modo de concurrencia "fija" se comprueban en función de las propiedades de la base de datos).

¿Las claves foráneas con nulos/tipos primitivos no son totalmente compatibles con las entidades de seguimiento automático para EF? Si no, ¿estoy obligado a usar entidades ficticias en lugar de nulas o hay otras soluciones?

actualización he tratado de reproducir el problema sin STE, pero EF llanura parece manejar la concurrencia optimista bien para las claves externas anulables, por lo que este es un problema de STE, no un problema de EF. Existen numerosos problemas con las entidades de auto-seguimiento, por lo que no es sorprendente que haya un problema aquí. Si encuentro una solución alternativa que pueda implementarse en el script STE T4, la publicaré aquí.

Respuesta

0

Sí, las claves foráneas con nulo están permitidas. Los usamos por todo el lugar. No muestra su base de datos o modelo, por lo que es difícil estar seguro de cuál podría ser el problema, pero parece que Entity Framework no puede descifrar la clave principal de una de las tablas involucradas. Tal vez no tienes uno, tal vez porque uno de ellos es una vista? Estoy adivinando aquí, porque no das mucha información sobre lo que estás haciendo.

+0

Estoy bastante seguro de que mis claves principales están bien. El problema ocurre cuando cambio la entidad referida que admite nulos a una nueva entidad. Esto hace que la referencia de entidad original (nulo) y la clave (nulo) se almacenen en la colección de valores originales. Cuando se solicita ApplyChanges, se intentan mover los valores desde el rastreador de cambios de entidades al contexto EF, pero dado que el contexto EF define el tipo de clave como Int32 y no anulable como entidad de autoperfil, no se puede asignar nulo . – Holstebroe

+0

Las columnas int nullable deben estar en su CSDL como 'int?', No 'int'. Pruébalo con una nueva tabla (previamente no asignada); verás. ¿Ha cambiado la capacidad de anulación desde que creó el modelo? –

+0

Intenté crear una nueva entidad "FooEntity" sin clave principal y un int32 nulo llamado Foo. Esto es lo que se genera en el CSDL: Sin Int32? aquí. ¿Cambiando Int32 a Int32? provoca un error "¿El valor 'Int32?' no es válido según su tipo de datos 'http://schemas.microsoft.com/ado/2008/09/edm:TPropertyType' – Holstebroe

Cuestiones relacionadas