Entity framework 未加载的实体框架双向关系包括

Entity framework 未加载的实体框架双向关系包括,entity-framework,ef-code-first,breeze,Entity Framework,Ef Code First,Breeze,这让我觉得自己像个白痴。实体框架应该相当简单,但我自己无法解决这个问题,显然我有一个基本的误解。我希望这不是一个愚蠢的问题——如果是的话,我很抱歉 三个代码优先对象,彼此相关 public class Schedule { [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid RowId { get; set; } public DateTime Start { get; set; }

这让我觉得自己像个白痴。实体框架应该相当简单,但我自己无法解决这个问题,显然我有一个基本的误解。我希望这不是一个愚蠢的问题——如果是的话,我很抱歉

三个代码优先对象,彼此相关

public class Schedule
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid RowId { get; set; }
    public DateTime Start { get; set; }
    public DateTime End { get; set; }

    public virtual ICollection<Charge> Charges { get; set; }
}

public class Charge
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid RowId { get; set; }
    public decimal Rate { get; set; }
    public Type Type { get; set; }
}

public class Type
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid RowId { get; set; }
    public string TypeName { get; set; }
}
因为virtual是一个导航属性,所以它应该使Breeze现在能够在不改变数据结构的情况下在关系中双向运行。但EF不喜欢这样。它告诉我:

无法确定服务器之间关联的主体端 类型“Core.Charge”和“Core.Type”。其主要目的是 必须使用 API或数据注释之间的关系

很公平。我能看出这是多么令人困惑。现在,我的理解是,如果在依赖类中定义外键,它必须是该类的主键。因此,我们将其改为:

public class Type
{
    [Key, ForeignKey("Charge"), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid RowId { get; set; }
    public string TypeName { get; set; }
    public virtual Charge Charge { get; set; }
}
这似乎有效,但。。。当您请求计划时,它将停止加载任何类型信息。在包裹上乱搞似乎一点作用也没有


发生了什么事,我做错了什么?

你确定要把ForeignKey放在RowId上,我想你可能想要定义这样的关系

public class Type
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid RowId { get; set; }
    public string TypeName { get; set; }
    public int ChargeId { get; set; }
    [ForeignKey("ChargeId")]
    public virtual Charge Charge { get; set; }
}

您不仅向现有模型/关系添加了导航属性(
Type.Charge
)。相反,您已将关系从一对多完全更改为一对一关系,因为默认情况下,如果一个关系只有一个导航属性,EF将采用一对多关系。通过更改,您已经配置了一对一关系

这些关系具有不同的外键:原始的一对多关系在
Charge
表中有一个单独的外键(可能命名为
Type_RowId
或类似名称)。新关系的外键位于表
Type
的另一侧,它是主键
RowId
。与
计划一起加载的
费用
可能没有任何具有相同主键的相关
类型
,因此不会加载
类型

如果您确实希望仅在另一端使用导航属性来重现旧的(一对多)关系,则必须将集合添加到
Type
,而不是单个引用:

public class Type
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid RowId { get; set; }
    public string TypeName { get; set; }
    public virtual ICollection<Charge> Charges { get; set; }
}
公共类类型
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
公共Guid RowId{get;set;}
公共字符串类型名{get;set;}
公共虚拟ICollection费用{get;set;}
}

感谢您的帮助。那你怎么称呼钥匙呢?“ChargeId”不是模型中任何属性的名称。尝试了“Charge”和“RowId”-这两种方法都会再次导致“无法确定关联的主体端”错误。您可以在类型模型中定义键名。好的,我的理解完全不正确。我曾假设,如果两端都没有指定为集合,EF将产生一对一的关系——这就是这里电荷和类型之间所需要的全部关系。回到文档中。@mattstrower:One-to-One意味着没有两个
Charge
s可以拥有相同的
类型。在您的业务逻辑中是这样吗?不是在同一个计划中,不是。一个计划有许多费用,每个费用必须是不同的类型。类型与费用在一个单独的表中,只是因为它在其他地方使用,否则它们可能是同一对象的一部分。@mattstrower:但是如果
Charge1
Schedule1
中,而
Charge2
在另一个
schedule2
中,这两种费用可以具有相同的类型吗?如果是,您肯定不能在
费用
类型
之间使用一对一关系。它必须是一对多。单个计划中的carges类型必须唯一的限制是应用程序业务逻辑,您无法通过任何映射配置来确保这一点。当然,您是正确的。打勾。我敢肯定,当我使用SQL来绘制它时,这似乎更容易。谢谢
public class Type
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid RowId { get; set; }
    public string TypeName { get; set; }
    public int ChargeId { get; set; }
    [ForeignKey("ChargeId")]
    public virtual Charge Charge { get; set; }
}
public class Type
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid RowId { get; set; }
    public string TypeName { get; set; }
    public virtual ICollection<Charge> Charges { get; set; }
}