简体   繁体   English

实体更新时,实体框架不会更新外键

[英]Entity Framework not updating foreign key when entity updates

I'm using Entity Framework with Web API 2. I have a boat entity with properties like name, price etc. Those simple properties update fine when sent by Put to the web api controller. 我正在将Entity Framework与Web API 2一起使用。我有一个Boat实体,其属性如名称,价格等。当由Put发送到Web api控制器时,这些简单的属性可以很好地更新。 The boat entity also has a many to one relationship with an entity called BoatType. 船实体还与称为BoatType的实体具有多对一关系。 Boat types are "Yacht", "Motor Yacht" etc. 船只类型为“游艇”,“机动游艇”等。

When a boat entity is updated in the controller the foreign key for boat type in the database doesn't get updated. 在控制器中更新船实体时,数据库中船类型的外键不会更新。 Do I have to somehow manually update the child entity value or is there a way to get EF to do this automatically? 我是否必须以某种方式手动更新子实体值,或者是否有办法让EF自动执行此操作?

Here's an example PUT request sent to web API: 这是发送到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
}

Here's the update function in web API: 这是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);
}

I've looked at similar questions like Entity Framework Code First Update Does Not Update Foreign Key , Entity Framework does not update Foreign Key object and Update foreign key using Entity Framework but none seem to have quite the same scenario (or the answers didn't help me understand my issue). 我看过类似的问题,例如实体框架代码“第一次更新不更新外键” ,“ 实体框架不更新外键对象”“使用实体框架更新外键”,但是似乎没有一个完全相同的场景(或者答案没有帮助我了解我的问题)。

Here's the Boat and BoatType model classes (auto-generated by EF designer). 这是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; }
}

Ok, I figured out what the problem was. 好的,我找出了问题所在。 Using SQL Server Profiler to look at the SQL Update statement I saw that the foreign key for Boat.BoatType wasn't even in there - so I figured my model must be screwed up somewhere. 使用SQL Server Profiler查看SQL Update语句,我发现Boat.BoatType的外键甚至不在其中-因此,我认为我的模型必须在某个地方搞砸了。 When I created the model in the designer, I mistakenly set the relationship between Boat and BoatType as one to one. 在设计器中创建模型时,我错误地将Boat和BoatType之间的关系设置为一对一。 I later realised the mistake and changed the association to one (BoatType) to many (Boats) but that must have been AFTER I generated the database. 后来我意识到了这个错误,并将关联从一个(BoatType)更改为许多(Boats),但这一定是在生成数据库之后进行的。 D'oh! 天哪! Something about the way EF handles associations meant that simply changing the association type in the diagram wasn't enough - I should have dropped/recreated the database constraint at that time. 关于EF处理关联的方式,这意味着仅更改图中的关联类型是不够的-那时我应该删除/重新创建数据库约束。

Since I only had test data in the database what worked for me was to recreate the database using the "Generate database from model..." option in the designer. 由于我只有数据库中的测试数据,因此对我有用的是使用设计器中的“从模型生成数据库...”选项重新创建数据库。

Once I got the PUT working correctly the other thing I had to solve (which is not really on topic for this question but it's been discussed above so just in case it's useful to someone) was that Web API gave the error "A referential integrity constraint violation occurred: The property value(s) of 'Boat.BoatTypeId' on one end of a relationship do not match the property value(s) of 'Boat.BoatType.Id' on the other end.". 一旦我让PUT正常工作,我就不得不解决另一件事(这个问题并不是真正的话题,但是上面已经讨论过,以防万一它对某人有用)是Web API给出了错误“参照完整性约束发生冲突:关系的一端“ Boat.BoatTypeId”的属性值与另一端“ Boat.BoatType.Id”的属性值不匹配。” The select list that allows the user to change the boat type is bound on the client using AngularJS to Boat.BoatType. 使用AngularJS在客户端上将允许用户更改船型的选择列表绑定到Boat.BoatType。 So in the PUT data, Boat.BoatType had been updated to new values but Boat.BoatTypeId hadn't changed - hence the "referential integrity" error. 因此,在PUT数据中,Boat.BoatType已更新为新值,但Boat.BoatTypeId并未更改-因此出现“参照完整性”错误。 So I just manually set the value of Boat.BoatTypeId to Boat.BoatType.Id before sending the PUT and all works as expected now. 因此,我只是在发送PUT之前手动将Boat.BoatTypeId的值设置为Boat.BoatType.Id,并且所有工作现在都按预期进行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM