【问题标题】:Entity Framework not updating foreign key when entity updates实体更新时实体框架不更新外键
【发布时间】:2015-12-20 02:05:01
【问题描述】:

我正在使用带有 Web API 2 的实体框架。我有一个带有名称、价格等属性的船实体。当 Put 发送到 Web API 控制器时,这些简单的属性会更新得很好。船实体还与称为 BoatType 的实体具有多对一关系。船型有“游艇”、“机动游艇”等。

当控制器中的船实体更新时,数据库中船类型的外键不会更新。我是否必须以某种方式手动更新子实体值,或者有没有办法让 EF 自动执行此操作?

以下是发送到 Web API 的 PUT 请求示例:

{
  "$id":"1",
  "Images":[],
  "BoatType": {
    "$id":"3",
    "Boat":[],
    "Id":1,
    "DateCreated":"2015-09-15T13:14:39.077",
    "Name":"Yacht"
  },
  "Id":2,
  "Name":"Schooner",
  "Description":"A harmless schooner",
  "DateCreated":"2015-09-15T17:59:37.8",
  "Price":65000
}

这是 Web API 中的更新函数:

[ResponseType(typeof(void))]
public async Task<IHttpActionResult> Put(int id, Boat boat)
{
    if (id != boat.Id)
    {
        return BadRequest();
    }

    _db.Entry(boat).State = EntityState.Modified;

    try
    {
        await _db.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!BoatExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }
    return StatusCode(HttpStatusCode.NoContent);
}

我查看过类似的问题,例如 Entity Framework Code First Update Does Not Update Foreign KeyEntity Framework does not update Foreign Key objectUpdate foreign key using Entity Framework,但似乎没有一个问题完全相同(或者答案没有帮助我理解我的问题)。

这是 Boat 和 BoatType 模型类(由 EF 设计器自动生成)。

public partial class Boat
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Boat()
    {
        this.Images = new HashSet<Image>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public System.DateTime DateCreated { get; set; }
    public Nullable<double> Price { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Image> Images { get; set; }
    public virtual BoatType BoatType { get; set; }
} 

public partial class BoatType
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public BoatType()
    {
        this.Boat = new HashSet<Boat>();
    }

    public int Id { get; set; }
    public System.DateTime DateCreated { get; set; }
    public string Name { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Boat> Boat { get; set; }
}

【问题讨论】:

  • "...在控制器中更新,数据库中船型的外键未更新"。那么,您是否在船对象中传递了有效的船类型 ID?与您的问题无关:除了包含 id 的船对象之外,您为什么还要传入 id ?看起来很奇怪。
  • 您是否在模型上定义了 FK,即,Boat 是否包含名为 BoatTypeID 的属性以及 BoatType 的属性?
  • 是的,上面显示的 PUT 中的 BoatType Id 为 1 是有效的。
  • ..."除了包含 id 的船对象之外,您为什么还要传入 id"。你是说 $id 属性吗?答案是我不知道为什么!查看对 GET 请求的响应,它也有 $id 属性,所以我猜这被 EF 作为某种索引包含在内。
  • 不,该模型没有船的 BoatTypeID 属性。 IE。要获得该值,我必须使用boat.BoatType.Id

标签: c# entity-framework asp.net-web-api2


【解决方案1】:

好的,我发现了问题所在。使用 SQL Server Profiler 查看 SQL Update 语句,我发现 Boat.BoatType 的外键甚至不在其中 - 所以我认为我的模型一定是在某个地方搞砸了。在设计器中创建模型时,我错误地将Boat 和BoatType 的关系设置为一对一。后来我意识到这个错误并将关联更改为一个(BoatType)到多个(Boats),但这一定是在我生成数据库之后。哦! EF 处理关联的方式意味着仅更改图表中的关联类型是不够的 - 我当时应该删除/重新创建数据库约束。

由于我在数据库中只有测试数据,所以对我有用的是使用设计器中的“从模型生成数据库...”选项重新创建数据库。

一旦我让 PUT 正常工作,我必须解决的另一件事是 Web API 给出了错误“A发生参照完整性约束违规:关系一端的“Boat.BoatTypeId”的属性值与另一端的“Boat.BoatType.Id”的属性值不匹配。”。允许用户更改船类型的选择列表在客户端上使用 AngularJS 绑定到 Boat.BoatType。因此,在 PUT 数据中,Boat.BoatType 已更新为新值,但 Boat.BoatTypeId 并未更改 - 因此出现“参照完整性”错误。所以我只是在发送 PUT 之前手动将 Boat.BoatTypeId 的值设置为 Boat.BoatType.Id,现在一切正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多