实体框架创建与现有实体关系的新实体,导致尝试创建现有实体的新副本

Ama*_*son 21 c# entity-framework

我正在尝试创建具有特定角色的新用户对象."角色"是EF中的现有实体.我用谷歌搜索了,并且堆栈溢出,直到我脸色发青,我已经尝试了所有似乎对其他人都有用的东西.但是当我尝试保存我的新用户对象时,它首先尝试创建一个新的"角色",而不是仅仅创建一个引用现有角色的新用户对象.

我究竟做错了什么?

Role myRole = new Role { ID = myUser.Role.ID };
myObjectContext.Roles.Attach(myRole);
myUser.Role = myRole;

if (myUser.ID == 0)
{
    myObjectContext.Users.AddObject(myUser);
}
else
{
    if (myUser.EntityState == System.Data.EntityState.Detached)
    {
        myObjectContext.Users.Attach(myUser);
    }
    myObjectContext.ObjectStateManager.ChangeObjectState(myUser, System.Data.EntityState.Modified);
}
myObjectContext.SaveChanges(SaveOptions.None);
Run Code Online (Sandbox Code Playgroud)

编辑 - 更多测试后......

好吧..所以我无论如何都发现了"原因"的某些部分.我仍然不知道为什么会这样做并需要帮助.

基本上,我附加到我的新User对象有两组数据.一个是"角色",它是包含角色的角色表的FK.这在用户上显示为"User.Role"的导航属性.

第二组数据是名为"FIPS"的对象集合,它们是用户与另一个名为FIPS的表之间的多对多关系.它们之间有一个关系表,它只包含两列,每列分别是User和FIPS的外键.用户的FIPS也是一个导航属性,引用类似"User.FIPS".

以下是整个代码,显示在保存上下文之前将FIPS和角色分配给User对象.

List<string> fipsList = new List<string>();
foreach (FIPS fips in myUser.FIPS)
{
    fipsList.Add(fips.FIPS_Code);
}
myUser.FIPS.Clear();
foreach (string fipsCode in fipsList)
{
    FIPS myFIPS = new FIPS { FIPS_Code = fipsCode };
    myObjectContext.FIPSCodes.Attach(myFIPS);
    myUser.FIPS.Add(myFIPS);
}


Role myRole = new Role { ID = myUser.Role.ID };
myObjectContext.Roles.Attach(myRole);
myUser.Role = myRole;


if (myUser.ID == 0)
{
   myObjectContext.Users.AddObject(myUser);
}
else
{
   if (myUser.EntityState == System.Data.EntityState.Detached)
   {
       myObjectContext.Users.Attach(myUser);
   }
   myObjectContext.ObjectStateManager.ChangeObjectState(myUser, System.Data.EntityState.Modified);
}

myObjectContext.SaveChanges(SaveOptions.None);
Run Code Online (Sandbox Code Playgroud)

我设置我的手表以检查"myObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added)"的状态,以查看何时向其添加内容.

只要将第一个Related对象添加到User对象,就会将尚未附加到上下文的第二个Related对象添加到EntityState为"Added"的上下文中.

....看看是否有办法避免将相关实体附加到用户实体,直到它们全部附加到上下文之后.

--FOLLOWUP-- 好的......我改变了代码的顺序,以便在分配给用户实体之前将相关实体附加到上下文..但是一旦分配了第一个相关实体,第二个相关实体在ObjectStateEntries中显示为"已添加".那么,我把它改成了以下顺序:

  1. 将所有相关实体附加到上下文.
  2. 将用户对象上的现有关系移除到相关实体类型.
  3. 将相关实体分配给用户实体.
  4. 保存用户实体.

而且..现在..它的工作..它的工作原理......!=)

Jef*_*ata 5

自从我编写下面的代码以来已经有一段时间了,但是我模糊地回忆起遇到同样的问题并且它正在发生,因为正在添加的角色当前正被上下文跟踪,因此附加存根具有添加新角色的效果相同的Id.

在下面的代码中,我检查第ChangeTracker一个,并在跟踪角色时使用现有条目.

// add roles that are in dto.Roles, but not in resource.Roles
// use the change tracker entry, or add a stub role
var rolesToAdd = fromDto.Roles.Where(r => !toResource.Roles.Any(role => role.Id == r)).ToList();
var roleEntries = dbContext.ChangeTracker.Entries<Role>();

foreach (var id in rolesToAdd)
{
    var role = roleEntries.Where(e => e.Entity.Id == id).Select(e => e.Entity).FirstOrDefault();

    if (role == null)
    {
        role = new Role { Id = id };
        dbContext.Set<Role>().Attach(role);
    }

    toResource.Roles.Add(role);
}
Run Code Online (Sandbox Code Playgroud)