实体框架双向关系不加载包括

时间:2013-07-19 13:32:12

标签: entity-framework ef-code-first breeze

这让我觉得自己像个白痴。实体框架应该相当简单,但我不能自己解决这个问题,显然我有一个根本的误解。我希望它不会成为一个白痴问题 - 对不起,如果是。

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

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; }
}

当我查询这个时,我想要所有相关的类型,所以:

        Schedule currentSchedule = _Context.Schedules
                .Include("Charges.Type")
                .Where(cs => cs.Start < dateWindow && cs.End > dateWindow)
                .First();

在C#中,这一直很好。

问题出现是因为我们没有停留在C#,而是将数据传递到名为Breeze的javascript库,并在客户端平滑数据操作。 Breeze有一个错误/功能,要求在两个端点指定对象之间的EF关系。因此,当我执行上述查询时,我最终没有任何类型,因为它们与Charge的关系没有直接指定。

所以我把它改成了这个:

public class Type
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid RowId { get; set; }
    public string TypeName { get; set; }
    public virtual Charge Charge { 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; }
}

这似乎有效,但......当你要求安排时,它已停止加载任何类型信息。乱搞包含似乎并没有做任何事情。

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

2 个答案:

答案 0 :(得分:2)

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

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

如果您确实想要仅使用另一侧的导航属性重现旧的(一对多)关系,则必须将集合添加到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; }
}

答案 1 :(得分:0)

你确定你想把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; }
}