gpt4 book ai didi

c# - 更新在 OwnsMany 值对象关系 EF Core 5 中不起作用

转载 作者:行者123 更新时间:2023-12-04 13:05:55 30 4
gpt4 key购买 nike

我有以下类(为简单起见减少了)。

public class User : Entity
{
public List<Skill> Skills { get; set; }
}

public class Skill : ValueObject
{
public string Name { get; private set; }
}

我的 UserConfiguration 类如下:

public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder
.OwnsMany(user => user.Skills);
}
}

在这里我说 EF 我的 User 类拥有一些 Skills 并且它生成下表: Skill Table

我使用工作单元模式,所以在我的存储库中,我对我的 Update 方法执行以下操作:

public virtual void Update(T entityToUpdate)
{
_context.Entry(entityToUpdate).State = EntityState.Modified;
}

更新后,我调用了我的 Commit 方法,它保存了更改:

public void Commit()
{
_dbContext.SaveChanges();
}

据我所知,在获取 User 实体时,我正确接收了所有属性(包括 Skills),但在更新时正在更新除了 Skills 之外的每个属性。

我尝试手动设置 Skill's 表主键和外键以这种方式更改 UserConfiguration 类(结果相同,技能未更新):

public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder
.OwnsMany(user => user.Skills, skill =>
{
skill.WithOwner().HasForeignKey("UserId");
skill.Property<int>("Id");
skill.HasKey("id");
});
}
}

我还尝试将我的 Update 方法更改为:

public virtual void Update(T entityToUpdate)
{
_dbSet.Update(entityToUpdate);
}

但我收到以下异常:Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException:数据库操作预计会影响 1 行但实际上会影响 0 行。

注意 Skill 是一个 ValueObject(它有一个影子 ID)。我实际上认为应该存在问题。

非常感谢您的帮助。

编辑:由于@pejman 的回答对我不起作用,我将把我的工作单元、存储库和上下文(为简单起见进行了缩减)放在这里,因为这是我唯一没有做过的事情,比如@ pejman,也许问题就在那里,但我看不到它。

存储库:

class BaseRepository<T> : IRepository<T> where T : Entity
{
private readonly Context _context;
private readonly DbSet<T> _dbSet;

public BaseRepository(Context context)
{
_context = context;
_dbSet = context.Set<T>();
}

public virtual T GetById(Guid id) => _dbSet.AsNoTracking().FirstOrDefault(x => x.Id == id);

public virtual void Update(T entityToUpdate)
{
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
}

工作单元:

public class UnitOfWork : IUnitOfWork
{
private const int SqlObjectAlreadyExistsErrorNumber = 2627;
private readonly Context _dbContext;
private BaseRepository<User> _users;

public UnitOfWork(Context dbContext)
{
_dbContext = dbContext;
}

public IRepository<User> Users
{
get
{
return _users ??= new BaseRepository<User>(_dbContext);
}
}

public void Commit()
{
_dbContext.SaveChanges();
}
}

上下文:

public class Context : DbContext
{
public Context(DbContextOptions<DeribeContext> options)
: base(options)
{
}

public DbSet<User> Users { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(DeribeContext).Assembly);
base.OnModelCreating(modelBuilder);
}
}

最佳答案

更新断开实体的集合导航属性的支持非常有限。首先,它们不被视为实体数据的一部分。其次,对于在断开连接的实体中找不到的现有子实体应该做什么还不是很清楚。

所有这一切都是因为 EF Core 没有关于原始数据库状态的信息,因为在它们主要支持的(也是唯一可靠的)加载流(在数据库上下文更改跟踪器中)、修改、保存中。

理论上,自有实体类型的集合应该比常规实体的集合更容易处理。由于它们被认为是所有者的一部分(至少在加载时),它们可以在更新期间被这样处理,即通过首先删除所有退出然后插入(添加)所有传入来替换。

实际上(当前的 EF Core)在断开连接的情况下更新它们几乎是不可能的。不仅它们不会自动处理,而且由于您无法定义 DbSet (因此使用 Set<T>() 方法)拥有的实体类型,没有其他方法可以告诉 EF Core 通过实际从数据库加载它们并清除集合来删除现有实体。这与显式/延迟加载不起作用的事实一起,留下了从数据库加载所有者实体的唯一选择。

一旦你这样做了,那么最好也应用修改后的属性(使用 CurrentValues.SetValues 方法),而不是使用“强制更新”,这一切在使用 Update 时都会发生。方法(或将 State 设置为 EntityState.Modified )。

将它应用到你的示例模型会是这样的

var dbUser = _context.Set<User>().FirstOrDefault(e => e.Id == user.Id);
_context.Entry(dbUser).CurrentValues.SetValues(user);
dbUser.Skills = user.Skills;

因为唯一的自定义代码是 dbUser.Skills = user.Skills; ,它可以通过使用 EF Core 提供的元数据和更改跟踪 API 推广到任何拥有的实体类型的集合:


public virtual void Update(T entityToUpdate)
{
// Load existing entity from database into change tracker
var entity = _dbSet.AsTracking()
.FirstOrDefault(x => x.Id == entityToUpdate.Id);
if (entity is null)
throw new KeyNotFoundException();
var entry = _context.Entry(entity);
// Copy (replace) primitive properties
entry.CurrentValues.SetValues(entityToUpdate);
// Copy (replace) owned collections
var ownedCollections = entry.Collections
.Where(c => c.Metadata.TargetEntityType.IsOwned());
foreach (var collection in ownedCollections)
{
collection.CurrentValue = (IEnumerable)collection.Metadata
.GetGetter().GetClrValue(entityToUpdate);
}
}

关于c# - 更新在 OwnsMany 值对象关系 EF Core 5 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69517251/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com