简体   繁体   English

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

[英]Entity Framework creating new entity with relationship to existing entity, results in attempt to create new copy of the existing entity

I am trying to create a new user object with a specific Role. 我正在尝试创建具有特定角色的新用户对象。 The "Role" is an existing entity in EF. “角色”是EF中的现有实体。 I have googled, and stackoverflowed until I am blue in the face, and I have tried all the stuff that seems to be working for everyone else. 我用谷歌搜索了,并且堆栈溢出,直到我脸色发青,我已经尝试了所有似乎对其他人都有用的东西。 But when I try to save my new user object, it first tries to create a new "Role", instead of just creating the new user object with a reference to the existing Role. 但是当我尝试保存我的新用户对象时,它首先尝试创建一个新的“角色”,而不是仅仅创建一个引用现有角色的新用户对象。

What am I doing wrong? 我究竟做错了什么?

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

EDIT - AFTER MORE TESTING... 编辑 - 更多测试后......

Ok.. so I have discovered some portion of the "cause" anyway. 好吧..所以我无论如何都发现了“原因”的某些部分。 I still don't know why it does this and need help. 我仍然不知道为什么会这样做并需要帮助。

Basically, there are two sets of data I am attaching to my new User object. 基本上,我附加到我的新User对象有两组数据。 One is the "Role" which is a FK to a Role table that contains the Role. 一个是“角色”,它是包含角色的角色表的FK。 This shows up as a navigation property on the User like "User.Role". 这在用户上显示为“User.Role”的导航属性。

The second set of data is a collection of objects called "FIPS", which are a many-to-many relationship between the User and another table called FIPS. 第二组数据是名为“FIPS”的对象集合,它们是用户与另一个名为FIPS的表之间的多对多关系。 There is a relationship table between them, that simply contains two columns, each a foreign key to User and FIPS, respectively. 它们之间有一个关系表,它只包含两列,每列分别是User和FIPS的外键。 The FIPS for a user are also a navigation property that is referenced like "User.FIPS". 用户的FIPS也是一个导航属性,引用类似“User.FIPS”。

Here is the whole code showing the assignment of the FIPS and Role to the User object prior to saving the context. 以下是整个代码,显示在保存上下文之前将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);

I set up my watch to check the status of "myObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added)" to see when things were being added to this. 我设置我的手表以检查“myObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added)”的状态,以查看何时向其添加内容。

As soon as the first Related object is added to the User object, the second Related object that hasn't yet been attached to the context, is added to the context with an EntityState of "Added". 只要将第一个Related对象添加到User对象,就会将尚未附加到上下文的第二个Related对象添加到EntityState为“Added”的上下文中。

.... Gonna see if there is a way to avoid attaching the related entities to the User entity until after they have all been attached to the context. ....看看是否有办法避免将相关实体附加到用户实体,直到它们全部附加到上下文之后。

--FOLLOWUP-- Ok.. well I changed the order of the code so that the related entities were attached to the context before being assigned to the User entity.. but as soon as the first related entity is assigned, the second related entity is shown as "added" in the ObjectStateEntries. --FOLLOWUP--好的......我改变了代码的顺序,以便在分配给用户实体之前将相关实体附加到上下文..但是一旦分配了第一个相关实体,第二个相关实体在ObjectStateEntries中显示为“已添加”。 So, then I changed it to the following order: 那么,我把它改成了以下顺序:

  1. Attach all related entities to context. 将所有相关实体附加到上下文。
  2. Remove existing relationships on the user object to related entity types. 将用户对象上的现有关系移除到相关实体类型。
  3. Assign related entities to user entity. 将相关实体分配给用户实体。
  4. Save user entity. 保存用户实体。

And.. now.. it works.. omg it works... ! 而且..现在..它的工作..它的工作原理......! =) =)

It's been a while since I wrote the code below, but I vaguely recall running into the same problem and it was occurring because the role being added was currently being tracked by the context, so attaching the stub has the effect of adding a new role with the same Id. 自从我编写下面的代码以来已经有一段时间了,但是我模糊地回忆起遇到同样的问题并且它正在发生,因为正在添加的角色当前正由上下文跟踪,因此附加存根具有添加新角色的效果相同的Id。

In the following code, I check the ChangeTracker first and use an existing entry if the role is being tracked. 在下面的代码中,我首先检查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);
}

This is how I did it in my case. 这就是我在我的情况下做到的。

Its a similar case where Item contains ICollection<Attribute> .Here no update is done , adding already existing attribute to the item is needed. 它是一个类似的情况,其中Item包含ICollection<Attribute>这里没有更新,需要在item添加已存在的attribute

First I looped through each attribute inside the item . 首先,我looped遍历item每个attribute

I had to first detach it from the local 我不得不先把它从当地拆下来

    context.Set<Model.Attribute>().Local                                           
                     .Where(x => x.Id == attr.Id)
    .ToList().ForEach(p => context.Entry(p).State = EntityState.Detached);

Then I attached . 然后我附上了。

      context.Set<Model.Attribute>().Attach(attr);

Then I reloaded the datas to it . 然后我将数据重新加载到它。

      context.Entry(attr).Reload();

Why are you creating a new instance of your Role entity if it already exists in the database? 如果您的Role实体已存在于数据库中,为什么要创建它的新实例?

Anyway, if you want to manually attach your new instance to the context, it should work if the ID of the attached instance exists in the database. 无论如何,如果要将新实例手动附加到上下文,如果数据库中存在附加实例的ID,则它应该有效。 But in your case the following lines are a bit strange: 但在你的情况下,以下几行有点奇怪:

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

You first create a new Role that has an ID that comes from an existing Role instance ( myUser.Role ) then you attach your new instance then finally you affect again your instance to the user it comes from. 首先创建一个具有来自现有Role实例( myUser.Role )的ID的新角色,然后附加新实例,最后再次影响您的实例到它来自的用户。 There's definitely something wrong here. 这里肯定有问题。 If your Role already exists (and it appears to be the case here as you wrote myUser.Role.ID on the first line, so I assume), why are you creating a new instance. 如果您的角色已经存在(并且在第一行写了myUser.Role.ID时似乎就是这种情况,那么我假设),为什么要创建一个新实例。

Drop those 3 lines. 丢掉这3行。 Get your Role from the database. 从数据库中获取您的角色。 Then affect the Role that comes from the database to the myUser.Role property. 然后影响来自数据库的RolemyUser.Role属性。

Try using this instead of the first three lines (which shouldn't be necessary at all, if the user object already knows it's role's ID and is discarded anyway): 尝试使用它而不是前三行(如果用户对象已经知道它的角色的ID并且被丢弃,则根本不需要这样做):

int id = myUser.Role.ID; // Role should be NULL, if the user is actually new...
                         // could it be that you wanted to write myUser.RoleID?
Role myRole = myObjectContext.Roles.FirstOrDefault(x => x.ID == id);
myUser.Role = myRole;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM