Entity Framework 4.1 - 非键列之间的关系

Posted

技术标签:

【中文标题】Entity Framework 4.1 - 非键列之间的关系【英文标题】:Entity Framework 4.1 - Relationships between non-key columns 【发布时间】:2011-11-03 00:16:13 【问题描述】:

我有 2 个相关的实体,但旧版 sql 模式本质上对同一个表有 2 个键列(不是 2 列键:见下文)。我需要创建与“假键”列的关系。有没有办法在 Entity Framework 4.1 中以声明方式执行此操作?

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

我得到的错误是:

*在模型生成过程中检测到一个或多个验证错误: System.Data.Edm.EdmAssociationConstraint: : 所有的类型 引用约束的 Dependent Role 中的属性必须是 与 Principal Role 中的相应属性类型相同。 实体“ClientLocation”上的属性“ClientCode”类型不 匹配实体 'Client' 上的属性 'ClientID' 的类型 引用约束“ClientLocation_Client”。*

因为它认为我正在尝试映射 ClientLocation.ClientCode > Client.ClientID,而当我真正尝试映射 ClientLocation.ClientCode > Client.ClientCode.. .

有什么想法吗?

谢谢!

【问题讨论】:

"...遗留的 sql 模式本质上对同一个表有 2 个键列...":您的意思是 Client.ClientCode 是一个具有唯一性的列数据库中的索引?或者什么是“2个键列......但不是复合键”?你想以某种方式将ClientLocation.Client 映射到这个独特的列Client.ClientCode 表有2个有效key,但是第二个没有被识别为key,没有索引。例如,ClientID 可以是 4,ClientCode 可以是“FOGCREEK”。两者没有关联或依赖关系,它们只是碰巧都是独一无二的。是的,我需要使用 Client.ClientCode 映射回原始表,即使它没有在我的实体中标记为键。 啊,我明白了,那么ClientCode就是一个普通的专栏。唯一性只是由业务逻辑意外确保的。恐怕拉迪拉夫的回答才是硬道理。 【参考方案1】:

实体框架要求在主表中的整个主键和从属表中的对应列(外键)之间建立关系。

【讨论】:

所以根据您的理解,没有办法像“映射”表和列名一样“映射”关系? 您必须像在数据库中那样映射关系。如果您的数据库没有正确设置表,EF 将无法修复它。 尽管这个答案可能是正确的,但我还不愿意在没有更多共识的情况下接受它。其他人可以验证没有类似于数据注释 和 的方法来帮助覆盖关系字段吗?
【参考方案2】:

(这只是拉迪斯拉夫答案的附录,accept和bounty一定不要去我的答案。)

如果在 EF 中实现这样的功能,我会感到惊讶。为什么?因为您甚至无法在关系数据库中创建这样的关系。关系数据库中的外键关系(至少是 SQL Server,可能是大多数或所有其他数据库)要求主体方是主键或具有唯一键约束的列。这是有道理的,因为外键应该引用主表中的一个唯一行

现在,EF 甚至还不支持与唯一键列的关系,只支持与主键列的关系。这是将来可能支持的东西。但是支持与非唯一和非主键列的外键关系对我来说似乎没有意义。

如果主表的目标列中的值不是唯一的,您预计会发生什么?当您尝试急切加载ClientLocation.Client - “由于外键未引用唯一目标而无法加载导航属性'Client'”时,您是否想要一个异常或警告“确实加载了一个客户端,但还有一个,不能确保我加载了你想要的”或类似的东西?

如果您想帮自己一个忙,我会放弃这个想法,删除导航属性并考虑在您的 LINQ 查询中大量使用 Join 的方向。

【讨论】:

【参考方案3】:

可能关联属性是您的答案,使用关联您可以指定要在关系的每一侧使用哪些键。

这样的一些代码:

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

如果我理解你的问题,你的代码应该改为:

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  

First "ClientCode" : ClientCode 中键列的名称。 第二个“ClientCode”:您要使用的 ClientCode 中键列的名称。

注意:我还没有使用过这个属性,但是它的文档和它的名字和它的参数名字表明它应该满足你的需要。

【讨论】:

我怀疑[Association] 属性在实体框架中是否有任何影响。它只是 LINQ to SQL 的映射属性。【参考方案4】:

即使不可能,您仍然可以像这样 (C#) 使用 LINQ 查询连接这两个表(另请参阅 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 ;

您只缺少导航属性 Client.ClientLocation 和 ClientLocation.Client。这样做有点麻烦,但还是可以的。

如果您愿意扩展 SQL 方案,您可以添加另一个表,例如 ClientLocationClient,它充当 M:N 表,外键同时指向 Client 和 ClientLocation,两者作为复合键。然后你可以像这样导航(C#)

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

但是,一旦您有一个没有相应客户端的 ClientLocation 并且当然您需要在 Client 中定义一个触发器来同步您的扩展表并将删除配置为级联并且 ClientLocation 需要是插入到客户端之前,否则触发器将失败...总的来说,我只想发出警告,这可能是一条非常危险的路线。

【讨论】:

以上是关于Entity Framework 4.1 - 非键列之间的关系的主要内容,如果未能解决你的问题,请参考以下文章

Entity Framework 4.1 两个跟踪查询

Entity Framework 4.1 InverseProperty 属性和ForeignKey

Entity Framework 4.1 Fluent API 属性

卸载 Entity Framework 4.1 六月 CTP

通过 Entity Framework 4.1 中的用户定义函数进行热切加载

Entity Framework 4.1 - 映射错误的模式