实体框架4.1 - 非关键列之间的关系

时间:2011-08-24 17:02:38

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

我有2个相关的实体,但遗留的sql架构基本上有2个关键列用于同一个表(不是2列密钥:见下文)。我需要创建一个回到'faux key'列的关系。有没有办法在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 ::所有类型   参照约束的从属角色中的属性必须是   与主体角色中的相应属性类型相同。   实体“ClientLocation”上的属性“ClientCode”没有   匹配实体'Client'中的属性'ClientID'的类型   引用约束'ClientLocation_Client'。*

因为它认为我正在尝试映射 ClientLocation.ClientCode&gt; Client.ClientID ,当我真的想要映射 ClientLocation.ClientCode&gt; Client.ClientCode ...

有什么想法吗?

谢谢!

4 个答案:

答案 0 :(得分:3)

实体框架要求在主表中的整个主键与依赖表的相应列(外键)之间建立关系。

答案 1 :(得分:2)

即使不可能,您仍然可以使用像这样的LINQ查询(C#)加入这两个表(另请参阅此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没有相应的客户端,此行就会失败。当然,您需要在客户端中定义触发器以同步您的扩展表并将删除配置为级联并且ClientLocation需要为在客户端之前插入,否则触发器将失败...总的来说,我只是想说出这可能是一条非常危险的路线。

答案 2 :(得分:0)

(这只是Ladislav答案的附录,接受和赏金一定不能回答我的答案。)

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

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

如果主表的目标列中的值不唯一,您期望会发生什么?您是否希望例外 - 例如 - 尝试加载ClientLocation.Client - “无法加载导航属性'Client',因为外键不引用唯一目标”或警告“加载了客户端但是还有另一个客户端,无法确保我加载了您想要的那个”或类似的东西?

如果你想帮自己一个忙,我会放弃这个想法,删除导航属性,并在你的LINQ查询中考虑与Join一起工作的方向。

答案 3 :(得分:0)

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

有些代码如下:

[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中的键列名称。

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