添加相关实体

时间:2016-06-21 19:09:38

标签: entity-framework entity-framework-core

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

例如,假设我有两个表:一个用于人(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();

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

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

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

链接到CROSSPOST

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

2 个答案:

答案 0 :(得分:0)

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

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

tu更新地址我会将代码更改为

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会为您处理。

答案 1 :(得分:0)

在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有值。