无法更新实体框架中的多对多关系
本文关键字:关系 框架 更新 实体 | 更新日期: 2023-09-27 18:32:36
>我首先使用实体框架 4.3 代码,并且在更新多对多关系时遇到问题。
我定义了以下类:
public abstract class Entity
{
[Column(Order = 0)]
[Key]
public int Id { get; set; }
[Timestamp]
[Column(Order = 1)]
public byte[] Version { get; set; }
}
public class Video : Entity
{
public string Title { get; set; }
public string Description { get; set; }
public TimeSpan Length { get; set; }
public virtual ICollection<Coworker> Coworkers { get; set; }
}
public class Coworker : Entity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Video> Videos { get; set; }
}
创建数据库时,架构看起来正确:还有一个视频,同事和视频同事表,没有
我在 N 层应用程序中使用存储库模式来访问数据库,我的插入和更新方法如下所示:
public T Insert(T entity)
{
//Creates database context. When it disposes, it calls context.SaveChanges()
using (var session = new DatabaseSession())
{
session.Context.Set<T>().Add(entity);
}
}
public T Update(T entity)
{
//Creates database context. When it disposes, it calls context.SaveChanges()
using (var session = new DatabaseSession())
{
entity = session.Context.Set<T>().Attach(entity);
session.Context.Entry(entity).State = EntityState.Modified;
}
return entity;
}
当我更新实体时,我从 DTO 创建实体对象,这就是使用 DbSet.Attach 而不是选择它并逐个更新属性的原因。
初始化数据库时,我添加了一些测试数据:
- 创建 3 个同事,我在其中设置名字和姓氏。(甲、乙、丙(
- 创建 3 个视频,在其中设置标题、描述和长度,并设置一些同事。第一个视频有A,B,第二个有B,C,第三个有A,C。
当我列出来自代码的视频时,我可以看到 Video.Coworkers 集合填充了良好的值,当我在 SQL Server Management Studio 中查询链接表(视频同事(时,它看起来也不错。
我的问题是例如,当我更新视频的标题时,它可以工作。但是当我尝试从 Video2 中删除现有同事(B 和 C(并尝试添加同事 A 时,关系不会更新。当我只尝试添加新同事或仅尝试删除一个同事时,它也不起作用。我通过创建一个新的视频实体来创建用作 Update(( 方法参数的实体,其中包含新的同事集合(这些同事是通过 Id 从带有 Find(( 方法的数据库中选择的(。
更新多对多关系的正确方法是什么?
但是当我尝试从 Video2 中删除现有的同事(B 和 C(时, 并尝试添加同事 A,则关系不会更新。
如果不使用通用存储库,正确的过程是:
using (var session = new DatabaseSession())
{
video2 = session.Context.Set<Video>().Include(v => v.Coworkers)
.Single(v => v.Id == video2Id);
coworkerA = new Coworker { Id = coworkerAId };
session.Context.Set<Coworker>().Attach(coworkerA);
video2.Coworkers.Clear();
video2.Coworkers.Add(coworkerA)
session.Context.SaveChanges();
}
必不可少的部分是,您必须以原始状态加载或附加实体,更改实体,即删除和添加子项,然后保存更改。EF 的更改检测将为链接表条目创建必要的 INSERT 和 DELETE 语句。将状态设置为Modified
在泛型Update
方法中尝试的简单过程仅适用于更新标量属性(如更改视频标题(,但不适用于更新实体之间的关系。
要解决此问题:
- 将实体附加到上下文 加载
- 集合(集合未加载,因为(
- 将实体的状态更改为已修改
- 保存更改
所以你的更新代码应该是这样的:
public Video Update(Video entity)
{
//Creates database context. When it disposes, it calls context.SaveChanges()
using (var session = new DatabaseSession())
{
entity = session.Context.Set<Video>().Attach(entity);
session.Context.Entry(entity).Collection(p => p.Coworkers).Load();
session.Context.Entry(entity).State = EntityState.Modified;
}
return entity;
}
请参阅此处,了解如何先使用数据库将主详细信息保存在 asp.net mvc 中。希望它能首先让您了解代码。你也可以看看knokout.js的例子