实体框架6:更新关系的问题

时间:2014-01-28 14:46:42

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

我目前正致力于使用ASP.NET Web API 2和实体框架6代码优先的REST API。

方案

我会尝试使用示例实体产品类别尽可能减少它。

// "Root" type.
// /api/products
public class Product
{
    public int ProductId { get; set; }

    public string Name { get; set; }

    // We are not exposing foreign key,
    // we want to update the Picture while updating the Product.
    public virtual Picture PrimaryPicture { get; set; }

    // Pictures collection should also update
    // while Product is being updated.
    public virtual ICollection<Picture> Pictures { get; set; }

    // We don't want the entire Category object returned,
    // but we do want an ID so we can always look it up whenever.
    public int CategoryId { get; set; }
    public virtual Category Category { get; set; }
}

// Note how all references are expressed as DTO's. I use AutoMapper for this.
// This is what the Web API returns.

public class ProductDto
{
    public int ProductId { get; set; }
    public string Name { get; set; }

    // PrimaryPicture is returned in Product response,
    // so should also be updatable from same API.
    public PictureDto PrimaryPicture { get; set; }

    // Pictures are returned in Product response,
    // so should also be updatable from same API.
    public ICollection<PictureDto> Pictures { get; set; }

    // Note we only have the category ID in the DTO
    // - hence, that's all we get from the API.
    public int CategoryId { get; set; }
}


// Root type
// /api/categories
public class Category
{
    public int CategoryId { get; set; }

    public string Name { get; set; }

    public virtual ICollection<Product> Products { get; set; }
}

public class CategoryDto
{
    public int CategoryId { get; set; }
    public string Name { get; set; }

    // We don't want all products when we query for categories.
}

// Not a root type.
public class Picture
{
    public string Url { get; set; }
    public string Title { get; set; }
}

public class PictureDto
{
    public string Url { get; set; }
    public string Title { get; set; }
}

我的API控制器接受DTO类型,并返回DTO类型。他们使用AutoMapper从DTO类型映射到EF使用的实际实体。这很好用,但是......

问题是,当我发布一个包含足够信息的更新(PUT /api/products/1)以将其映射到相应的DTO时,DTO未公开的字段将为空。

示例:请参阅产品实体。它有PrimaryPicturePictures,DTO也是如此。 DTO 具有Category,因此当映射到实体时,Category为空,但CategoryId是它应该是的

这是更新中发生的事情:

  • API控制器从Dto映射到实体。
  • 我的存储库从数据库中提取要更新的实体,并使用 AutoMapper 将更新的值(从第一步开始)应用到从DB获取的实体,这将在EF中将其标记为脏。好。
  • SaveChanges();

当Entity Framework尝试保存Product实体时,它会看到Category为null,但CategoryId具有非零值,表示存在关系,然后地狱断开(异常时间!)。

我在步骤2中使用DbContext.Entry(product).CurrentValues.SetValues(updatedProduct)而不是AutoMapper解决了这个问题,但是它不会映射图片集合或PrimaryPicture中的更改,因为SetValues仅适用于标量属性,而不适用于导航。

我试图保持尽可能通用,是否可以这样做而无需为我们拥有的每种实体类型手动更新相关对象?

我缺少EF的特定配置吗?

0 个答案:

没有答案
相关问题