在实体框架中保存数据+关系数据的最佳/最简便方法

时间:2018-08-02 22:34:34

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

请考虑实体框架中这种简单的一对多关系。一个组织拥有许多产品。

public class Product
{
    public int Id { get; set; }

    [StringLength(20)]
    public string Title { get; set; }

    [StringLength(300)]
    public string Description { get; set; }

    public float Price { get; set; }
    public DateTime CreationDate { get; set; }

    public virtual Organisation Organisation { get; set; }

    public Product()
    {
        CreationDate = DateTime.Now;
    }
}

public class Organisation
{
    public int Id { get; set; }

    [StringLength(20)]
    public string Title { get; set; }

    [StringLength(400)]
    public string Description { get; set; }

    public DateTime CreationDate { get; set; }

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

如果有一个(后)api调用,则在主体中接受原始数据(json格式的文本),这使用户可以在同一调用中创建组织和所需的任意数量的产品。如何使用Entity Framework将这些数据正确保存到数据库中?

据我所知,我正在使用延迟加载(由于在模型中设置关系时使用了虚拟关键字),所以它不应该自动处理关系吗?如果我像下面的控制器动作(post调用的控制器动作)那样保存数据。能行吗如果没有,使用Entity Framework保存/保存包含另一个模型列表的模型的适当/最佳实践方法是什么。

public IHttpActionResult CreateOrganisation(Organisation org)
{           
    db.Organisations.Add(org);
    db.SaveChanges();
    return Ok(org);
}

真的似乎无法在文档中找到这个吗?

3 个答案:

答案 0 :(得分:0)

好吧,我没有时间尝试,但是查看您的代码,我发现如果您正在寻找最佳实践,即使您的问题没有得到解决,我还是会向您指出一些建议:

  1. 使用“异步任务”模式使​​您的Web API控制器避免死锁:

    public async Task<IHttpActionResult> CreateOrganisation(Organisation org) 
    
  2. 使调用方方法(即ef的业务逻辑)与上述相同。在这种情况下,请使用SaveChangesAsync()方法。当在您的控制器中调用任何方法时,请不要忘记使用关键字await。

  3. 使用关注点分离。将BL应用于Controller类之外。

  4. 应用SOLID原理。倒置的依赖性(例如,使用Microsfot Unity IOC容器的字母D)使类使用抽象类,接口松散地耦合,因此在此之后应用注入的依赖性。

  5. 尝试使用视图模型来验证模型,而不是使用EF的datafirst模型或代码优先的模型来验证域类。

  6. 最后但并非最不重要的一点是,强键入!!!!

我希望这些建议对您有所帮助。

答案 1 :(得分:0)

由于您要求“最佳实践”,因此我将向您介绍当EF对对象图的处理量很少时,我必须使用的一种技术,我们是否应该说“ iffy”?

首先,每个物理存储的实体都有一个对应的DTO对象。 ViewModel的一部分(讲MVVM)是该View必需的DTO对象。为每个实体添加了其他字段来传达状态(UI所做的事情)。看起来像这样:

public class ProductDTO {
    // Same fields, mostly
    public string Action { get; set; }    // A, C, D
}

public class OrganizationDTO {
    // Same fields except children
    public ICollection<ProductDTO> Products { get; set; }
    public string Action { get; set; }
}

基于顶级DTO,POST,PUT或DELETE(A,C,D)中的非空白操作。 UI设置每个实体的状态。对孩子的修改被视为对父项的“更改”。

然后在后端的CRUD方法中……不可否认,这是大锤方法。

public class OrganizationRepository : whatever interfaces {
    public void Add (OrganizationDTO newOrg) {
        if (newOrg.Action != "A")    // Why are you here?
           throw an exception (bad request)

        context.Organizations.Add(Map DTO to entity here);
        foreach (var item in newOrg.Products) {
            switch (item.Action)
            case "A":
                ProductRepository.Add(item,newOrg.Id);
                break;
            case "C":
                ProductRepository.Update(item,newOrg.Id);
                break;
            case "D":
                ProductRepository.Delete(item);
                break;
        }
        context.SaveChanges();
    }

    public void Update (OrganizationDTO oldOrg) {
        if (newOrg.Action != "C")    // Why are you here?
           throw an exception (bad request)

        context.Organizations.Attach(Map DTO to entity here);
        foreach (var item in newOrg.Products) {
            switch (item.Action)
            case "A":
                ProductRepository.Add(item,newOrg.Id);
                break;
            case "C":
                ProductRepository.Update(item,newOrg.Id);
                break;
            case "D":
                ProductRepository.Delete(item);
                break;
        }
        context.SaveChanges();
        return Ok();
    }
}

这不是正常工作/未经测试的代码。只是粗糙的现成。必须处理添加的FK。添加您的映射技术。处理冲突,尝试/捕获等。

答案 2 :(得分:-1)

我认为您的代码不太容易说明。
如果我是一名开发人员,正在研究您在此处发布的方法,我简直不明白我有可能发送嵌套数据。

我将对对象“ org”的Products集合进行迭代,然后将其添加到其EF集合中,然后再将Organization添加到其自身中。

然后显然是SaveChanges()。

这显然可以将这种接受嵌套对象的方法与另一种认为并不能简单地保存我新的空组织的假想方法区分开来。