【问题标题】:Update entity foreign key after adding related entity添加相关实体后更新实体外键
【发布时间】:2016-06-22 22:15:31
【问题描述】:

我正在尝试了解如何第一次更新一条记录并将相关实体添加到该记录,然后使用新创建的相关记录中的外键更新原始记录。

例如,假设我有两张表:一张用于人员 (tbl_person),另一张用于地址 (tbl_address)。

+----+------------+-----------+-----------+
| PK | First Name | Last Name | AddressFK |
+----+------------+-----------+-----------+
|  1 | Michael    | Jordan    |         1 |
|  2 | Lebron     | James     |           |
+----+------------+-----------+-----------+

    public int PersonID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int? AddressID { get; set; }
    public virtual tbl_Address tbl_Address { get; set; }

    entityBuilder
        .HasOne(t => t.tbl_Address)
        .WithOne(t => t.tbl_Person)
        .HasForeignKey<tbl_Person>(d => d.AddressID)
        .IsRequired(false);

+----+-------------------+----------+-------+
| PK |  Address Line 1   |   City   | State |
+----+-------------------+----------+-------+
|  1 | 123 Sesame Street | New York | NY    |
+----+-------------------+----------+-------+

    public int AddressID { get; set; }
    public string AddressLine1 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public virtual tbl_Person tbl_Person { get; set; }

我的应用收到以下需要更新的 JSON 记录。

{
  "address": {
    "addressLine1": "789 Hollywood Ave",
    "city": "Hollywood",
    "state": "CA"
  },
  "firstname": "Lebron",
  "lastname": "Brown",
  "id": 2,
}

我需要将 Lebron James 更新为 Lebron Brown,并添加他的地址。现在我搜索记录并执行以下操作,它会更新 Person 记录并创建一个地址记录:

var person = _db.tbl_Person
    .Include(t => t.tbl_address)
    .Where(t => t.Id == json.id).First();

person.firstname = json.firstname;
person.lastname = json.lastname;
if(person.tbl_Address == null)
{
    person.tbl_Address = new tbl_Address() {
        AddressLine1 = json.address.addressLine1,
        City = json.address.city,
        State = json.address.state,
    };
}

db.SaveChanges();

问题是当我尝试在保存更改之前使人员 addressID 等于新创建的 addressID 时,它会给我一个关于外键约束的错误。

person.AddressID = person.tbl_Address.Id;
db.SaveChanges();

任何帮助将不胜感激。谢谢

交叉发布链接

我最终交叉发布到 EntityFramework Core Github,因为我开始认为这可能是一个错误,因为它没有像预期的那样在子实体中自动生成外键。 GitHub 上的问题附有示例项目(比此处显示的示例稍微复杂一些),如果您想检查它,则会复制错误:https://github.com/aspnet/EntityFramework/issues/5833

【问题讨论】:

  • 带有数据注释或 EntityTypeConfigurations 的类声明会有所帮助,但基本上您不会手动更新 FK,因为当时(在 SaveChanges 调用之前)它们都采用默认值(default(int) == 0 ) 这就是为什么会有例外。
  • 嗯,这更像是我的问题的一个示例。但它与我的实际表格相当接近。我按要求添加了类声明。
  • 在您的示例中,通过设置person.tbl_Address,EF 将插入地址并自行更新Person

标签: entity-framework entity-framework-core


【解决方案1】:

如果您的模型设置正确,则无需设置 AddressID。它将自动更新。在 SaveChanges() 调用之前,AddressID 的值为default(int) == 0 - 这就是发生异常的原因。这个声明就足够了:

public class Person {
    public int AddressID {get;set;}
    [ForeignKey(nameof(Person.AddressID))]
    public Address tbl_Address {get;set;}
}

你更新地址我会把代码改成

if (json.address != null) 
{
    if(person.tbl_Address == null)
    {
        person.tbl_Address = new tbl_Address();
    }
    person.tbl_Address.AddressLine1 = json.address.addressLine1,
    person.tbl_Address.City = json.address.city,
    person.tbl_Address.State = json.address.state
}

这样,如果人已经有一个地址,它将更新,否则创建新的。无需设置外键 - EF 为您处理。

【讨论】:

  • 我最初认为我不必定义 addressID,直到我运行它并按预期创建地址但从未将 addressID 添加到人员表中。我的表格略有不同,我只是简化了业务逻辑以专注于问题,但总体而言是相同的。我正在做一个快速愚蠢的项目来测试这些示例表,看看我是否得到相同的结果
  • 我已更新示例以根据需要执行更新/插入。
  • 我最终交叉发布到 EntityFramework Core Github,因为我开始认为这可能是一个错误,因为它没有像预期的那样在子实体中自动生成外键。 GitHub 上的问题有示例项目被攻击,如果您想检查它,则会复制错误:github.com/aspnet/EntityFramework/issues/5833
  • 我将此标记为帮助其他人的答案,因为它确实回答了这个问题。我的问题是 EntityFramework Core RC2 Final 中的一个错误。最初我没有尝试显式分配 FK,因为从历史上看,我知道 Entity Framework 应该按照您的描述处理它。更新到最新的 RTM 位后,我的表现在可以正确更新
【解决方案2】:

在 EF 中有两种设置关系的方法,

  • 设置 FK 属性:当实体已存在于您的数据库中时使用此变体。

  • 设置导航属性:如果是新实体,请使用此变体。当您调用SaveChanges 时,新实体将保留在您的数据库中,并且FK 列也将被设置。

所以,如果 Address 已经存在,您只需搜索其 Id 并在您的 Person 实体中设置 FK 属性。

如果Address不存在,则创建一个新实例并调用SaveChanges

person.tbl_Address = new tbl_Address() {
    AddressLine1 = json.address.addressLine1,
    City = json.address.city,
    State = json.address.state,
};
db.SaveChanges();

在那次调用之后,您应该能够看到AddressId 在您的Person 实体中有一个值。

【讨论】:

  • 但在我的情况下,该人存在且地址不存在我该怎么办?我需要更新此人的姓氏并导航到地址并首次添加地址,但还要将该 addressID 返回给该人并更新该表
  • 嗨@chris,你看到我回答的最后一部分了吗?
  • 我最终交叉发布到 EntityFramework Core Github,因为我开始认为这可能是一个错误,因为它没有像预期的那样在子实体中自动生成外键。 GitHub 上的问题有示例项目被攻击,如果您想检查它,则会复制错误:github.com/aspnet/EntityFramework/issues/5833
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-20
  • 2021-12-04
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多