【问题标题】:EF Core adding Parent and Child in same transactionEF Core 在同一事务中添加父级和子级
【发布时间】:2020-02-13 11:28:02
【问题描述】:

我有标准的父/子设计:

class Parent {
    Guid Id;
    List<Child> Children;

    public Parent() {
        Id = Guid.NewGuid();
        this.Children = new List<Child>();
    }

    public AddChild(Child ch) {
        this.Children.Add(ch);
    }
}

class Child {
    Guid Id;

    public Child() {
        Id = Guid.NewGuid();
    }
}

我的映射是这样的:

public void Configure(EntityTypeBuilder<Parent> builder)
{
    builder.ToTable("Parents");
    builder.HasKey(x => x.Id);

    builder.HasMany(p => p.Children)
        .WithOne()
        .HasForeignKey("ParentId");
}

public void Configure(EntityTypeBuilder<Child> builder)
{
    builder.ToTable("Children");
    builder.HasKey(x => x.Id);
}

现在,在我的服务方法中(将子添加到父级,在系统中不存在的情况下创建父级):

var parent = await _parentsRepository.GetParent(parentId);

if (parent == null)
{
    parent = new Parent();
    await _parentsRepository.AddAsync(customerMembersip); // adding parent to context, with empty Children collection, but not saving to DB yet
}

parent.AddChild(new Child()); // this make this new Child in Parent object to be in state "Modified", but in fact should be in state "Added". Why?

// save changes here

换句话说,为什么将子级添加到父级(父级只是添加到上下文中)会使子级被视为已修改?但是,如果我从 repo 中获取父级并且它立即在上下文中,然后我添加子级,那么子级将被视为 已添加

编辑:

这可能是因为 Id(Guid 类型)是在 C# 代码中生成的,因此 EF“认为”它是现有实体,因此将其标记为“已修改”。但我不太明白为什么,如果 Parent 已经存在于 DB 中(_parentsRepository 返回实际实体)

【问题讨论】:

  • (1) 请重命名您的“Id”以区分它们。 ParentId(或ParentKey)和ChildId(或ChildKey。(2)我认为您需要添加互惠关系。(在Child.configure上)示例: this.HasRequired(t => t.Parent) .WithMany(t => t .Children) .HasForeignKey(d => d.ParentKey);
  • 继续。您的 Child 对象需要像“Parent MyParent {get;set}”这样的属性。然后在您的方法“public AddChild(Child ch)”上,您需要添加一个新行 .. 类似“ch.MyParent = this;”
  • 我会尝试这种方法,但它违反了 DDD,因为在我的业务案例中,我根本不需要双向关系。仅仅因为 EF 不喜欢“预生成的 Guid”而增加一点复杂性并不适合我。
  • EF 是关于“互惠”关系的,至少在我的经验中是这样。如果您想(仅)添加一个子项,那么数据库如何知道父项的 FK 是什么? (没有 Child 上的“Parent MyParent {get;set}”属性?)
  • 互惠是在映射(配置文件)级别定义的。根据我的经验,在您的域模型中不需要有双向关系。

标签: entity-framework ef-core-2.2


【解决方案1】:

回答我自己的问题。

在 Asp.net core 3.0(因此是 EF Core 3.0)中,您需要将 Child 的映射从:

public void Configure(EntityTypeBuilder<Child> builder)
{
    builder.ToTable("Children");
    builder.HasKey(x => x.Id);
}

到:

public void Configure(EntityTypeBuilder<Child> builder)
{
    builder.ToTable("Children");
    builder.Property(x => x.Id).ValueGeneratedNever(); // change is here!
}

希望对其他人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-23
    • 2020-03-21
    相关资源
    最近更新 更多