2015-09-22 192 views
0

我正在使用实体框架和Web API 2.我有一个名称,价格等属性的船只实体。这些简单的属性更新时发送通过放到网络API控制器。船实体也与称为BoatType的实体有多对一的关系。游艇类型为“游艇”,“摩托游艇”等。当实体更新时,实体框架不更新外键

当船舶实体在控制器中更新时,数据库中船型的外键不会更新。我是否需要手动更新子实体值或者是否有办法让EF自动执行此操作?

这里发送到网络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 
} 

下面是网络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; } 
} 
+0

“...在控制器中更新数据库中船型的外键不会更新”。那么,你是否在船对象中传入了有效的船型ID?与您的问题无关:除了包含ID的船对象外,您为什么还要传入ID?似乎很奇怪。 – Sam

+0

您是否在模型上定义了FK,即Boat是否包含名为BoatTypeID的属性以及BoatType的属性? – Sam

+0

是的,上面显示的PUT中的1的BoatType Id是有效的。 – Danzig

回答

1

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

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

一旦我得到了PUT正常工作,我必须解决的另一件事(这不是真的关于这个问题的主题,但它已在上面讨论过,以防万一它对某人有用)是Web API给出错误“发生了参照完整性约束冲突:关系一端的'Boat.BoatTypeId'的属性值与另一端的'Boat.BoatType.Id'的属性值不匹配。“。允许用户更改船型的选择列表绑定在客户端上,使用AngularJS对Boat.BoatType。因此,在PUT数据中,Boat.BoatType已更新为新值,但Boat.BoatTypeId未更改 - 因此“参照完整性”错误。因此,我只是在发送PUT之前手动将Boat.BoatTypeId的值设置为Boat.BoatType.Id,并且所有工作都按预期工作。