实体框架DbContext Confusion当两个外键指向同一个表时

时间:2017-08-06 12:21:48

标签: c# entity-framework entity-framework-6

public partial class MyDbContext : DbContext
{
    public MyDbContext()
        : base("name=Model1")
    {
    }

    public virtual DbSet<User> Users { get; set; }
    public virtual DbSet<UserGroup> UserGroups { get; set; }
    public virtual DbSet<UserGroupMember> UserGroupMembers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) { }
}

[Table("gnr.UserGroup")]
public partial class UserGroup
{
    public UserGroup()
    {
        ChildUserGroups = new HashSet<UserGroupMember>();
        UserGroupMembers = new HashSet<UserGroupMember>();
    }

    public long ID { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }

    [InverseProperty("ChildUserGroup")]
    public virtual ICollection<UserGroupMember> ChildUserGroupMembers { get; set; }

    [InverseProperty("UserGroup")]
    public virtual ICollection<UserGroupMember> UserGroupMembers { get; set; }
}

[Table("gnr.UserGroupMember")]
public partial class UserGroupMember
{
    public long ID { get; set; }
    public long? UserID { get; set; }
    public virtual User User { get; set; }

    [ForeignKey("UserGroup")]
    public long UserGroupID { get; set; }
    public virtual UserGroup UserGroup { get; set; }

    [ForeignKey("ChildUserGroup")]
    public long? ChildUserGroupID { get; set; }
    public virtual UserGroup ChildUserGroup { get; set; }

}

[Table("gnr.User")]
public partial class User
{
    public User()
    {
        UserGroupMembers = new HashSet<UserGroupMember>();
    }

    public long ID { get; set; }
    public string Username { get; set; }
    public string MobileNumber { get; set; }
    public virtual ICollection<UserGroupMember> UserGroupMembers { get; set; }
}


        static void Main(string[] args)
    {
         WorkNotCorrectly();

        Console.WriteLine("Done");

        Console.ReadLine();
    }

    private static void WorkNotCorrectly()
    {
        using (var db = new MyDbContext())
        {
            var ug = new UserGroup { Title = "It's a new UserGroup 1" };

            var cugm = new UserGroupMember { ChildUserGroupID = 1 };

            ug.ChildUserGroupMembers.Add(cugm);

            // After This Line
            db.UserGroups.Add(ug);

MyDbContext设置&#39; ChildUserGroup&#39; &#39; cugm&#39;的财产反对&#39; ug&#39;

但预期的行为是设置&#39; UserGroup&#39; &#39; cugm&#39;的财产反对&#39; ug&#39;

&#39;微克&#39;对象Json:

{
"ID": 0,
"Title": "It's a new UserGroup 1",
"Description": null,
"ChildUserGroupMembers": [
    {
        "ID": 0,
        "UserID": null,
        "User": null,
        "UserGroupID": 0,
        "UserGroup": null,
        "ChildUserGroup": HERE IS THE PROBLEM => The MyDbContext sets the 'ChildUserGroup' property instead of 'UserGroup' property,
        "ChildUserGroupID": 1 
    }
],
"UserGroupMembers": []
}

SaveChanges:

            db.SaveChanges();
        }
    }

&#39;微克&#39;对象到SaveChanges之后的Json:

    {
    "ID": 2,
    "Title": "It's a new UserGroup 1",
    "Description": null,
    "ChildUserGroupMembers": [
        {
            "ID": 1,
            "UserID": null,
            "User": null,
            "UserGroupID": 2,
            "ChildUserGroupID": 2 WHAT???? IT IS CHANGED TO 2 ( THE NEW UserGroup THAT IS GENERATED),
            "ChildUserGroup": HERE IS THE PROBLEM => The MyDbContext sets the 'ChildUserGroup' property instead of 'UserGroup' property 
        }
    ],
    ????? WHAT IS THIS??? WHY UserGroupMembers PROPERTY IS FILLED
    "UserGroupMembers": [ 
        {
            "ID": 1,
            "UserID": null,
            "User": null,
            "UserGroupID": 2,
            "ChildUserGroupID": 2
        }
    ]
}

预期的行为和结果是:

    {
    "ID": 2,
    "Title": "It's a new UserGroup 1",
    "Description": null,
    "ChildUserGroupMembers": [
        {
            "ID": 1,
            "UserID": null,
            "User": null,
            "UserGroupID": 2,
            "UserGroup": 'The ug object with ID of 2 ',
            "ChildUserGroupID": 1
        }
    ]
}

Result in SSMS and the relationship diagram

似乎EF混淆了识别正确的FK,插入物体后必须自己填充的那个和我填充的那个?? !!

更新 这是实体之间的关系:

  1. UserGroupMember是UserGroup和User

  2. 之间的桥接表
  3. 每个用户都可以是1 ... * UserGroup

  4. 的成员
  5. 每个UserGroup可以有1 ... * User as member

  6. (直到这里它像一个普通的桥表来表示多对多的关系)

    4. 每个UserGroup可以有1 ... * ChildUserGroup作为成员

    (这意味着UserGroup可以将User或ChildUserGroup作为成员,例如“Windows的用户和组”)

    此致。

1 个答案:

答案 0 :(得分:0)

这里的主要问题是,您的代码设置的导航属性不如您期望的那样。

首先,您使用InverseProperty属性来定义您的关系。

  • UserGroup.ChildUserGroupMembers&amp; UserGroupMember.ChildUserGroup与外键属性ChildUserGroupID
  • 构成一种关系
  • UserGroup.UserGroupMembers&amp; UserGroupMember.UserGroup与外键属性UserGroupID
  • 构成另一种关系

在EF中定义关系时,有3个组件,主要依赖于导航,依赖于主导航&amp;外国财产。设定其中任何一个的价值也会决定其他人。如果设置任何导航,则外键属性将设置为与主键属性具有相同的值。如果导航已经加载到内存中,也会填充导航。

当SSMS输出显示时,您的UserGroup表中已有ID = 1的数据。 现在在你的代码中,

  • 您正在创建新的UserGroup ug
  • 您正在创建新的UserGroupMember cugm
  • 您正在设置cugm.ChildUserGroupID = 1的值。实体具有cugm.ChildUserGroup导航(与ChildUserGroupID fk相关联)的关系应该具有UserGroup ID = 1分配给它。由于它未加载到内存中,因此该导航将保持为空。同样,如果内存中加​​载ID = 1的UserGroup,则UserGroup.ChildUserGroupMembers集合会向其添加cugm
  • 然后您要将cugm添加到ug.ChildUserGroupMembers集合中。这意味着FK属性cugm.ChildUserGroupID应该取ug.ID的值。反向导航的cugm.ChildUserGroup应指向ug。从那时起EF不在图片中,在添加实体之前不会发生上述变化。
  • 然后您将ug添加到UserGroups数据库集,以便EF开始跟踪实体及其子项。由于ug.ChildUserGroupMembers集合中添加了cugm,因此EF会将cugm.ChildUserGroup设置为ugug对象仍有临时密钥,因此EF不会将ug.ID复制到cugm.ChildUserGroupID

这就是你获得第一个JSON的方式。它已设置ChildUserGroup,因为您设置了它的反向导航。

致电SaveChanges后, EF会将实体ug保存到数据库。由于您的数据库已经具有ID = 1的实体,因此它获得的下一个ID为2.由于ug.ID不再是临时值,cugm.ChildUserGroupID将获取其值并更改为2。< / p>

现在根据您的SSMS数据, 你想要创建新的UserGroup对象 - ug,保存后会得到ID = 2。您想要创建新的UserGroupMember对象 - cugm,它将获得ID = 1(带有标识列的第一行。)cugm.UserGroupId = 2因此cugm.UserGroup导航应设置为{ {1}}&amp; ug = 1。

这就是代码应该是什么样的

cugm.ChildUserGroupID

上面的代码将在您的数据库中生成您想要的精确记录。

var ug = new UserGroup { Title = "It's a new UserGroup 1" }; var cugm = new UserGroupMember { ChildUserGroupID = 1 }; ug.UserGroupMembers.Add(cugm); // You want to set UserGroupID = 2 so cugm should be added to its corresponding inverse navigation db.UserGroups.Add(ug); db.SaveChanges(); 对象的JSON输出如下(在你的问题中也是不正确的)

ug