【问题标题】:Entity Framework 4.1 - Relationships between non-key columnsEntity Framework 4.1 - 非键列之间的关系
【发布时间】: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就是一个普通的专栏。唯一性只是由业务逻辑意外确保的。恐怕拉迪拉夫的回答才是硬道理。

标签: .net vb.net entity-framework-4.1 vb.net-2010


【解决方案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 需要是插入到客户端之前,否则触发器将失败...总的来说,我只想发出警告,这可能是一条非常危险的路线。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-26
      • 2019-06-02
      相关资源
      最近更新 更多