实体框架在多对多关系中重复条目

Posted

技术标签:

【中文标题】实体框架在多对多关系中重复条目【英文标题】:Entity Framework duplicate entries in many to many relationship 【发布时间】:2015-11-16 16:34:20 【问题描述】:

我已经阅读了很多关于多对多实体框架问题的帖子,并且它再次让人头疼。

Colaborador 有一个 ICollection of Time 和 时间有一个Colaborador的集合

有人说在上下文中添加之前有必要附加子实体(对我不起作用,Pk 错误)。

我正在使用简单的注入器,我的上下文是每个请求的。

我的关联表是这样映射的:

            HasMany<Time>(c => c.Times)
            .WithMany(t => t.Colaboradores)
            .Map(ct =>
            
                ct.MapLeftKey("ColaboradorId");
                ct.MapRightKey("TimeId");
                ct.ToTable("Receptor");
            );

它在数据库中创建关联表。 当我尝试插入 Colaborador(entity) 时,我在其列表中添加了一些 Times(Teams),添加到 DbContext 然后 SaveChanges()。

当我这样做时,它会创建一个新的 Colaborador,在关联表(ID)中正确插入,但也会复制时间。

var colaborador = Mapper.Map<ColaboradorViewModel, Colaborador>(colaboradorVm);
List<TimeViewModel> timesVm = new List<TimeViewModel>();
colaboradorVm.TimesSelecionados.ForEach(t => timesVm.Add(_serviceTime.BuscarPorId(t)));

colaborador.Times = Mapper.Map<ICollection<TimeViewModel>, ICollection<Time>>(timesVm); 

函数 BuscarPorId 执行 Find 方法并返回一个时间。

我发现如果我调用 Add 命令,实体也会将孩子的状态标记为已添加,但如果我尝试附加时间或将其状态更改为未更改,我会得到一个主键错误...

foreach (var item in colaborador.Times)
                
    lpcContext.Set<Time>().Attach(item);
    //lpcContext.Entry(item).State = EntityState.Unchanged;

有没有办法告诉实体框架不要插入特定的孩子?所以只填充了主表和关联表?

【问题讨论】:

这与多对多关系无关。它总是发生。如果您需要避免添加相关实体,则需要从数据库中检索它们(与添加时使用的上下文相同)或将它们附加到上下文中,然后将 EntityState 设置为 Unchanged @Moho : 附加类型实体失败,因为另一个相同类型的实体已经具有相同的主键值。 @bubi,我使用 Find 方法检索时间,然后将其添加到 Colaborador 的列表中。就在添加上下文之前,我试图附加(就像上面显示的那样),但我得到了 Pk 错误。这不是正确的方法吗? 【参考方案1】:

Mapper.Map 创建新的 Time 对象,这些对象未附加到您的上下文,因此您必须将它们附加为 Unmodified,但附加它们会由于重复 PK 而导致另一个错误,因为您的上下文已经在跟踪Time 实体。使用Find 方法将检索这些跟踪和本地缓存的实体。

查找并使用已附加到您的上下文的实体:

代替:

colaborador.Times = Mapper.Map<ICollection<TimeViewModel>, ICollection<Time>>(timesVm);

用途:

var times = new List<Time>();
var dbSet = lpcContext.Set<Time>();

foreach( var t in timesVm )

    var time = dbSet.Find( t.Id );

    if( null == time )
    
        time = Mapper.Map<TimeViewModel, Time>( t );
    

    times.Add( time );


collaborador.Times = times;

【讨论】:

Moho,timesVm 已经有我需要的数据,但它在视图模型中(以前使用 _serviceTime.BuscarPorId()... BuscarPorId 执行 Find 方法)。是否真的需要再次为每个 id 做另一个 foreach ?因为在这一层我没有访问 DbSet(我调用服务为我做这件事),但我知道它们是相同的上下文(因为我将它们设置为每个请求) 您已经知道答案了,因为您的代码不起作用; Mapper.Map 创建新的 Time 对象,这些对象未附加到您的上下文,因此您必须将它们附加为 Unmodified,但由于重复 PK,附加它们会导致另一个错误,因为您的上下文已经在跟踪 @987654331 的原始副本@实体。使用Find 方法将检索这些跟踪和本地缓存的实体。 我终于明白了它是如何工作的,我要感谢@Moho。

以上是关于实体框架在多对多关系中重复条目的主要内容,如果未能解决你的问题,请参考以下文章

自跟踪实体 SaveChanges() 在多对多关系中添加实体时出现异常

实体框架:多对多插入重复

如何在多对多关系上使用休眠和 JPA 删除孤立实体?

NSPredicate 在多对多关系中

学说2:在多对多关系中引用连接表

具有多对多关系的级联删除[重复]