EntityFramework多个NavigationProperties到同一个表

时间:2014-04-23 19:48:05

标签: c# linq entity-framework sql-server-ce

所以我有两个表,一个有几个外键,都指向另一个表。

示例:

 TableA
 Id | FirstId | SecondId | ThirdId
 1  | 10      | 11       | 12
 2  | 13      | 14       | 15

 TableB
 Id | Value
 10 | 'Cat'
 11 | 'Dog'
 12 | 'Rabbit'
 13 | 'Bird'
 14 | 'Hamster'
 15 | null

现在我构建了一个查询,例如:

 var entity = context.TableA
     .Include(a => a.First)
     .Include(a => a.Second)
     .Include(a => a.Third)
     .SingleOrDefault(a => a.Id == 1)

现在,根据我构建查询的方式,我可以大致得到两个结果中的一个。如果我使用上面的示例,我将返回一个实体,但SecondId可能是11并且设置了所有正确的属性,但FirstId和ThirdId可能具有值15并且所有属性都将为null( Id是随机但一致的,并且对于所有查询始终相同,直到我重建数据库)。现在,如果我将SingleOrDefault(...)替换为:

 .With(a => a.Id == 1).SingleOrDefault()

我将分别返回一个实体,其FirstId,SecondId和ThirdId分别为10,11,12(正确),但只有a.Second会设置任何属性。 a.First.Value和a.Third.Value都将为null。此外,它始终是正确的SecondId,从不是第一或第三。

所以我的问题是,EntityFramework不支持单个表与另一个表有多个关系的想法,还是我缺少某些东西,或者?

我已经尝试检查LINQ生成的查询但是当我对数据库运行它时,我得到了所有正确的值。我尝试改变构建LINQ查询的方式,并且在使用.Include(...)和.Load()之间进行了交换。当我使用.Load()时,不正确的Ids(在我的第一个例子中为15)实际上会在每次调用.SaveChanges()时传播回数据库,即使我什么都没做但是:

 using(MyDatabase context = new MyDatabase())
 {
      context.TableB.Load();
      context.SaveChanges();
 }

我使用的是EntityFramework 6和一个SqlCE 4.0数据库。

TableA&的课程表B(注意这些是从edmx模型自动生成的):

public partial class TableA
{
    public int Id { get; set; }
    private int FirstId { get; set; }
    private int SecondId { get; set; }
    private int ThirdId { get; set; }

    public virtual TableB First { get; private set; }
    public virtual TableB Second { get; private set; }
    public virtual TableB Third { get; private set; }
}

public partial class TableB
{
    public int Id { get; set; }
    public string Value { get; set; }
}

我现在也尝试将提供程序从System.Data.SqlServerCe.4.0切换到System.Data.SqlClient(并将数据库移动到SQLExpress实例),我得到了相同的结果。

2 个答案:

答案 0 :(得分:0)

我认为生成的类有一点bug。您可以尝试更改下面的TableA,然后再试一次吗?

public class TableA
{
    public int Id { get; set; }
    [ForeignKey("First")]
    private int? FirstId { get; set; }
    [ForeignKey("Second")]
    private int? SecondId { get; set; }
    [ForeignKey("Third")]
    private int? ThirdId { get; set; }

    public virtual TableB First { get; private set; }
    public virtual TableB Second { get; private set; }
    public virtual TableB Third { get; private set; }
}

答案 1 :(得分:0)

所以我觉得自己像个白痴,但实际上我发现了这个问题。在我开始升级以使用EntityFramwork之前还有另一个部分类:

public partial class TableA
{
    public static readonly TableB DefaultTableBValue = new TableB(null);

    public TableA()
    {
        this.First = TableA.DefaultTableBValue;
        this.Second = TableA.DefaultTableBValue;
        this.Third = TableA.DefaultTableBValue;
    }
}

public partial class TableB
{
    public TableB(string value)
    {
        this.Value = value;
    }
}

这显然会混淆EntityFramework的对象映射器,当它实例化一个新对象时(在从数据库返回之前),它会看到First,Second和Third值发生变化,并尝试将它们提交回数据库或它不会复制'默认值',只是按原样返回对象。一旦我删除了这个不需要的部分课程,一切都完美无瑕。

长话短说,小心创建默认构造函数并修改任何数据库属性。 EntityFramework在检测到构造函数中的值更改时似乎不知道该怎么做。