【问题标题】:ASP.NET Core 3.1. problem with updating collectionASP.NET 核心 3.1。更新集合的问题
【发布时间】:2020-11-15 02:57:18
【问题描述】:

我将 ASP.NET Core 中的应用程序从 2.1 迁移到 3.1,但遇到 Entity Framework 问题。

我有一个带有GlassesLenses 集合的实体:

public class GlassesContract : BaseUpdateEntity, IAggregateRoot
{
    public Guid Id { get; private set; } = Guid.NewGuid();

    private readonly List<GlassesLenses> _glassesLenses = new List<GlassesLenses>();
    public ICollection<GlassesLenses> GlassesLenses => _glassesLenses.AsReadOnly().ToList();

    public void ClearLenses()
    {
        _glassesLenses.RemoveRange(0, _glassesLenses.Count);
    }

    public void AddLens(GlassesLenses lens)
    {
        _glassesLenses.Add(lens);
    }
}

还有更新镜头的服务:

public async Task<GlassesContract> ChangeSetting(GlassesContract contract)
{
    // clean lenses
    contract.ClearLenses();
    await _glassesContractRepository.UpdateAsync(contract);

    // add new lens
    contract.AddLens(new GlassesLenses());

    await _glassesContractRepository.UpdateAsync(contract);
    return contract;
}

在 2.1 版中,该行为运行良好。集合已清除(EF 标记实体以供删除)并添加新镜头 EF 标记作为新实体以供插入。

在 3.1 版中,EF Core 只进行更新,而不是删除和插入。

// delete lens
UPDATE public."GlassesContracts" 
SET "AccountId" = @p0, "BalancePaymentDeposit" = @p1, ...
WHERE "Id" = @p42 AND "SysRowVer" IS NULL
RETURNING "SysRowVer";

// add new lens
UPDATE public."GlassesContracts" 
SET "AccountId" = @p0, "BalancePaymentDeposit" = @p1, ...
WHERE "Id" = @p42 AND "SysRowVer" IS NULL
RETURNING "SysRowVer";

UPDATE public."GlassesLenses" 
SET "Availability" = @p43, "Color" = @p44, ...
WHERE "Id" = @p77 AND "SysRowVer" IS NULL
RETURNING "SysRowVer";

映射 DbContext:

// mapping relationship
    modelBuilder.Entity<GlassesContract>()
      .HasMany(_ => _.GlassesLenses)
      .WithOne(_ => _.GlassesContract)
      .OnDelete(DeleteBehavior.Cascade);
    
    modelBuilder.Entity<GlassesLenses>()
      .HasOne(_ => _.GlassesContract)
      .WithMany(_ => _.GlassesLenses);

// mapping Value objects
modelBuilder.Entity<GlassesLenses>().OwnsOne(o => o.Price).WithOwner();
modelBuilder.Entity<GlassesLenses>().OwnsOne(o => o.PriceExclVat).WithOwner();
modelBuilder.Entity<GlassesLenses>().OwnsOne(o => o.FinalPrice).WithOwner();
modelBuilder.Entity<GlassesLenses>().OwnsOne(o => o.FinalPriceExclVat).WithOwner();
modelBuilder.Entity<GlassesLenses>().OwnsOne(o => o.Discount).WithOwner();

如果我用AddAsync(entity)Remove(entity) 标记实体,这将生成正确的SQL 作为INSERT 和DELETE。

谁能解释一下为什么新版本 3.1 不如 v2.1 智能以及为什么 SysRowVer(并发令牌)总是 NULL 并且不更新?

非常感谢

更新

实体跟踪器在调用 AddLens(..) 后显示“实体 GlassesLens 已修改”。我不明白为什么 if 被添加为新的。

---已解决---

【问题讨论】:

  • 我找不到 contract.AddLens(new GlassesLenses());可以展示一下吗?
  • 谢谢。并且请添加 UpdateAsync 方法,因为这都是关于更新的。

标签: c# asp.net-core entity-framework-core


【解决方案1】:

在EF数据库上下文表映射中使用

modelBuilder.Entity<GlassesContract >(m =>
{
        m.OwnsMany(i => i.GlassesLenses); //instead of HasMany().WithOne()
});

有关OwnsMany的更多解释,请查看SO

【讨论】:

  • 谢谢,但这不是我的情况,因为 GlassesLenses 是不同的表实体而不是值对象:(
【解决方案2】:

我找到了解决方案(我的知识错误)。问题是 EF Core 3+ 中的重大更改。

我们使用 GUID 作为主键。这不是生成值,因为我们使用 DDD 规则和实体框架的应用程序改变了这种行为。

您需要告诉 EF 您的 ID 不是通过添加 DatabaseGenerated 属性生成的

[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; private set; } = Guid.NewGuid();

或精通 DbContext

modelBuilder
    .Entity<GlassesLenses>()
    .Property(e => e.Id)
    .ValueGeneratedNever();

上帝保佑this post

原来是

DetectChanges honors store-generated key values

谢谢大家

【讨论】:

    猜你喜欢
    • 2020-07-08
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 2021-06-26
    • 2017-08-25
    相关资源
    最近更新 更多