[英]Creating copy of entities with many to many relationship without duplicating one of the type
I have problem with copying entities with many to many relationship. 我在复制具有多对多关系的实体时遇到问题。 I have three entities Company , Role and User defined like this: 我有三个实体Company , Role和User定义如下:
Company: 公司:
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public virtual IList<User> Users { get; set; }
}
User: 用户:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public virtual IList<Role> Roles { get; set; }
}
Role: 角色:
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
public virtual IList<User> Users { get; set; }
}
Also, I defined many to many relationship between users and roles: 另外,我定义了用户和角色之间的多对多关系:
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
ToTable("TUser");
HasKey(x => x.Id);
HasMany(x => x.Roles).WithMany(x => x.Users).Map(m =>
{
m.MapLeftKey("UserId");
m.MapRightKey("RoleId");
m.ToTable("TUserRole");
});
}
}
I used migrations to create tables in db and obviously EF created table TUserRole (so far everything good). 我使用迁移在db中创建表,显然使用EF创建了表TUserRole(到目前为止一切正常)。
And now, I would like to create copy of company and users but without copying roles (so I want to create new records at the tables TCompany, TUser and TUserRole, but no new records at the TRole). 现在,我想创建公司和用户的副本,但不复制角色(因此,我想在表TCompany,TUser和TUserRole上创建新记录,但在TRole上没有新记录)。
I thought that something like this would work but I'm getting exception: 我以为这样的事情会奏效,但我遇到了例外:
Context context = new Context();
var company = context.Companies.Include(x => x.Users.Select(u => u.Roles)).AsNoTracking().SingleOrDefault();
context.Companies.Add(company);
foreach (var user in company.Users)
{
foreach (var role in user.Roles)
{
context.Entry(role).State = EntityState.Unchanged;
}
}
context.SaveChanges();
And the exception is Saving or accepting changes failed because more than one entity of type 'Mackas.EF.Model.Role' have the same primary key value. 例外是保存或接受更改失败,因为多个“ Mackas.EF.Model.Role”类型的实体具有相同的主键值。
I understand why I'm getting this (because there is more than one role with the same ID), but I don't know what should be my approach. 我知道为什么要得到这个(因为有多个具有相同ID的角色),但是我不知道应该采用什么方法。
Any suggestions? 有什么建议么?
I'm using EF 6.1.3. 我正在使用EF 6.1.3。
Using AsNoTracking
generally is a good idea to obtain a graph of entities that aren't attached to a context. 通常,使用AsNoTracking
是获取未附加到上下文的实体图的好主意。 As you know, adding the root entity ( company
) to a new context will mark all entities in the graph as Added
and copying entities is a piece of cake. 如您所知,将根实体( company
)添加到新的上下文中会将图形中的所有实体标记为“已Added
,复制实体简直是小菜一碟。
But there's one bummer. 但是,有一个令人讨厌。 AsNoTracking
causes EF to materialize a new object for each entity in the result set, because it has no way to track that an entity has already been materialized. AsNoTracking
导致EF为结果集中的每个实体实例化一个新对象,因为它无法跟踪某个实体已经实例化。 So you're OK as long as the object graph only diverges off the root entity. 因此,只要对象图仅偏离根实体,就可以。 Ie as long as all associations are 1 - 0..n
. 即,只要所有关联均为1 - 0..n
。 It that is true, all entities in the graph will represent exactly one "real" entity. 没错,图中的所有实体都将恰好代表一个“真实”实体。
However, in your case, there's a m - n
association between User
and Roles
. 但是,在您的情况下, User
和Roles
之间存在m - n
关联。 The graph converges . 该图收敛 。 If some users have the same roles, EF will create duplicate Role
objects when using AsNoTracking
. 如果某些用户具有相同的角色,则在使用AsNoTracking
时,EF将创建重复的Role
对象。
[By the way, contrary to EF6, EF-core manages to create unique entities even with AsNoTracking
] [顺便说一句,与AsNoTracking
相反,即使使用AsNoTracking
,EF-core也可以创建唯一的实体]
The way to go here is to query the object graph by one context, as POCOs, not proxies, and then add/attach it to a second context: 此处的方法是通过一个上下文(即POCO,而不是代理)查询对象图,然后将其添加/附加到第二个上下文:
Company company;
using (Context context = new Context())
{
context.Configuration.ProxyCreationEnabled = false;
company = context.Companies.Include(x => x.Users.Select(u => u.Roles))
.SingleOrDefault();
}
using (Context context = new Context())
{
context.Companies.Add(company);
foreach (var user in company.Users.SelectMany(u => u.Roles)
.Distinct())
{
context.Entry(role).State = EntityState.Unchanged;
}
context.SaveChanges();
}
Proxies have a reference to the context they were created by, so you can't attach them to a second context. 代理引用了创建它们的上下文,因此您不能将它们附加到第二个上下文。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.