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: : 引用约束的从属角色中所有属性的类型必须与主体角色中的相应属性类型相同。实体“ClientLocation”上的属性“ClientCode”类型与引用约束“ClientLocation_Client”中实体“Client”上的属性“ClientID”类型不匹配。*

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

有什么想法吗?

谢谢!

4

4 回答 4

3

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

于 2011-08-24T20:21:16.913 回答
2

即使不可能,您仍然可以使用这样的 LINQ 查询 (C#) 连接这两个表(另请参阅此问题)。

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 中定义一个触发器来同步您的扩展表并将删除配置为级联并且需要在客户端,否则触发器将失败......总的来说,我只想发出警告,这可能是一条非常危险的路线。

于 2011-09-30T15:27:55.463 回答
0

(这只是拉迪斯拉夫答案的附录,接受和赏金一定不要去我的答案。)

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

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

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

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

于 2011-09-23T19:19:20.353 回答
0

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

像这样的一些代码:

[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  

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

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

于 2011-09-28T01:01:45.230 回答