2011-08-24 35 views
13

Tengo 2 entidades relacionadas, pero el esquema sql heredado tiene esencialmente 2 columnas clave para la misma tabla (no una clave de 2 columnas: ver a continuación). Necesito crear una relación con la columna 'clave falsa'. ¿Hay alguna manera de hacerlo declarativamente en Entity Framework 4.1?Entidad Framework 4.1 - Relaciones entre columnas no clave

Public Class Client 
    Inherits ModelBase 

    <Key(), Required()> 
    Public Property ClientID As Decimal 

    <Required(), StringLength(50)> 
    Public Property ClientCode As String 

    ........ 


Public Class ClientLocation 
    Inherits ModelBase 

    ........ 

    <Required(), StringLength(50)> 
    Public Property ClientCode As String 

    ........ 

    <ForeignKey("ClientCode")> 
    Public Overridable Property Client As Clients.Client 

Y el error que estoy consiguiendo es: se detectaron

* Uno o más errores de validación durante la generación del modelo: System.Data.Edm.EdmAssociationConstraint:: Los tipos de propiedades en todas las el rol dependiente de una restricción referencial debe ser del mismo modo que los tipos de propiedad correspondientes en la función principal. El tipo de propiedad 'ClientCode' en la entidad 'ClientLocation' no se coincide con el tipo de propiedad 'ClientId' en la entidad 'Cliente' en el restricción de referencia 'ClientLocation_Client'. *

, ya que piensa que' m tratando de mapear ClientLocation.ClientCode> Client.ClientID, cuando yo estoy tratando de asignar ClientLocation.ClientCode> Client.ClientCode ...

¿Alguna idea?

Gracias!

+0

"* ... el esquema de SQL legado esencialmente tiene 2 columnas clave para la misma mesa ... *": ¿Quiere decir que 'Client.ClientCode' es una columna con un índice único en la base de datos? ¿O qué son entonces "2 columnas clave ... pero no clave compuesta"? ¿Y desea asignar 'ClientLocation.Client' de alguna manera a esta columna única' Client.ClientCode'? – Slauma

+0

La tabla tiene 2 claves efectivas, pero la segunda no está identificada como clave, y no tiene índice. Por ejemplo, ClientID podría ser 4 y ClientCode podría ser "FOGCREEK". Los dos no están relacionados o son dependientes, simplemente resultan ser únicos. Y sí, tendrá que asignar de nuevo a la tabla original con el Client.ClientCode, a pesar de que no está marcada como una clave en mi entidad. –

+0

Ah, ya veo, entonces 'ClientCode' es una columna ordinaria. La unicidad es garantizada accidentalmente por la lógica comercial. Me temo que la respuesta de Ladilav es la última palabra. – Slauma

Respuesta

3

El marco de entidad exige que la relación se genere entre la clave primaria completa en la tabla principal y las columnas correspondientes (clave externa) en la tabla dependiente.

+0

Entonces, según su comprensión, ¿no hay forma de "mapear" la relación de la misma manera que podemos "asignar" los nombres de las tablas y columnas? –

+0

Debe correlacionar la relación de la misma manera que lo haría en la base de datos. Si su base de datos no tiene tablas configuradas correctamente, EF no puede repararlas. –

+1

Aunque esta respuesta probablemente sea correcta, no estoy dispuesto a aceptarla aún sin más consenso. ¿Alguien más puede verificar que no existe un método similar a las anotaciones de datos y para ayudar a anular los campos de relación? –

0

(Esto es sólo un apéndice a la respuesta de Ladislav, aceptar y recompensa no tiene que ir a mi respuesta.)

Me sorprendería si una característica cada vez se llevará a cabo en la FE. ¿Por qué? Porque ni siquiera puedes crear esa relación en una base de datos relacional. Una relación de clave externa en una base de datos relacional (al menos SQL Server y probablemente la mayoría o la totalidad) exige que el lado principal sea una columna que sea , ya sea clave principal o tenga una restricción de clave única. Lo cual tiene sentido porque se supone que una clave foránea se refiere a una fila única en la tabla principal.

Ahora, EF ni siquiera admite relaciones con columnas clave únicas, solo a columnas de clave principal. Esto es algo que posiblemente podría ser apoyado en el futuro. Pero el hecho de admitir relaciones de claves externas con columnas no exclusivas y sin clave primaria ni siquiera parece tener sentido para mí.

¿Qué espera que suceda si el valor en la columna de destino de la tabla principal no es exclusivo? ¿Quieres una excepción cuando - por ejemplo - intenta cargar ansiosos ClientLocation.Client - "No se puede cargar navegación por la propiedad 'Cliente', porque la clave externa no se refiere a un objetivo único" o una advertencia "se ha cargado un cliente pero hay es otro, no puedo asegurarme de haber cargado el que quería " o algo así?

Si usted quiere hacer un favor me gustaría renunciar a la idea, quitar la propiedad de navegación y pensar en la dirección que trabajar mucho con Join en sus consultas LINQ.

0

Probablemente atributo Asociación es su respuesta, utilizando la asociación puede especificar qué teclas que se utiliza en cada lado de la relación.

Algunos código como este:

[ForeignKey()] 
[Association("SomeNameForAssociation","TheKeyInThisEntity","TheKeyOnTheAssociationTargetEntity")] 
public virtual Examination Examination { get; set; } 

Y si entiendo su pregunta, usted debe cambiar el código a:

Public Class Client 
    Inherits ModelBase 

    <Key(), Required()> 
    Public Property ClientID As Decimal 

    <Required(), StringLength(50)> 
    Public Property ClientCode As String 

    ........ 


Public Class ClientLocation 
    Inherits ModelBase 

    ........ 

    <Required(), StringLength(50)> 
    Public Property ClientCode As String 

    ........ 

    <ForeignKey("ClientCode")> 
    <Association("ClientClientCodes","ClientCode","ClientCode")> 
    Public Overridable Property Client As Clients.Client 

primero "ClientCode": nombre de la columna clave en ClientCode. Segundo "ClientCode": nombre de la columna clave en ClientCode que desea utilizar.

Nota: No he utilizado este atributo todavía, pero su documentación y su nombre y sus nombres de argumentos sugesst debe satisfacer sus necesidades.

+0

Dudo que el atributo '[Association]' tenga algún efecto en Entity Framework. Es solo un atributo de mapeo para LINQ to SQL. – Slauma

2

Incluso si no es posible que todavía se podía unir las dos tablas mediante una consulta LINQ como tal (C#) (véase también este question).

var result = from a in ctx.Client 
      join b in ctx.ClientLocation 
      on a.ClientCode equals b.ClientCode 
      select new { Client = a, Location = b }; 

Solo le falta la propiedad de navegación Client.ClientLocation y ClientLocation.Client. Es un poco más complicado hacerlo de esta manera, pero es posible sin embargo.

Si usted está dispuesto a ampliar el régimen de SQL se podría añadir otra mesa como ClientLocationClient que actúa como un M: N tabla con claves externas tanto para el cliente y ClientLocation y los dos como clave compuesta. A continuación, puede navegar como tal (C#)

var client = myClientLocation.ClientLocationClients.First().Client; // there's only one 

Esta línea sin embargo dejar tan pronto como usted tiene un ClientLocation que no tiene ningún cliente correspondiente y por supuesto que tendría que definir un disparador en el cliente para sincronizar su mesa de extensión y configure la eliminación para que sea en cascada Y se debe insertar ClientLocation antes que el Cliente; de ​​lo contrario, el desencadenador fallará ... En general, solo quiero expresar una advertencia de que esta puede ser una ruta bastante peligrosa.

Cuestiones relacionadas