【问题标题】:Best/easiest way to save data+relational data in Entity Framework在实体框架中保存数据+关系数据的最佳/最简单方法
【发布时间】:2018-08-02 22:34:34
【问题描述】:

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

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 将这些数据正确保存到数据库中?

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

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

在文档中似乎真的找不到这个?

【问题讨论】:

  • 会有用吗? - 你试过了吗?
  • 它是否有效并不重要。我只是把它放在那里向你展示我的意思。我正在寻找有关“最佳实践”方式的具体示例。
  • 如果可行 - 这是最佳实践。如果稍后您遇到问题(性能、可扩展性、可读性......) - 您将对其进行重构以消除问题,并且该代码将成为您的应用程序的最佳实践。最佳实践都是关于具体上下文的。在您提供的示例中,它应该足够有效且易于理解。
  • 我理解你的观点,但这不是真的。仅仅因为您不知道更好/更有效的做事方式,并不意味着它不存在。使用您的逻辑,每个解决方案都是最好的,直到您了解一个新的解决方案。如果这是真的,请将这篇文章视为我学习更好的方法。
  • 正如我所说的编程就是上下文。在您的问题的背景下 - 添加新组织就足够了。给我们一些具体的问题,可能会有更好的方法,

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


【解决方案1】:

好吧,我没有时间尝试它,但是查看您的代码,我发现如果您正在寻找最佳实践,我可能会向您指出一些建议,即使这些不回答您的问题:

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

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

  3. 利用关注点分离。从 Controller 类中应用 BL。

  4. 应用 SOLID 原则。反转的依赖,字母 D,例如使用 Microsfot Unity IOC 容器,使用抽象类、接口使类松散耦合,因此之后应用注入依赖。

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

  6. 最后一点,强类型!!!

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

【讨论】:

  • 谢谢。不过,我知道其中的大部分内容,我只是想举一个简单的例子来说明一点。希望获得一些保存关系数据的最佳方法的代码示例。这些课程实际上并不是我工作的一部分。
【解决方案2】:

既然你要求“最佳实践”,我会告诉你一个我在 EF 处理对象图时不得不使用的技术,我们应该说“不确定”吗?

首先,每个物理存储的实体都有一个对应的 DTO 对象。 ViewModel 的一部分(MVVM-speak)是该 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。添加您的映射技术。处理冲突、Try/Catch 等。

【讨论】:

    【解决方案3】:

    我认为您的代码不能很好地自我解释。
    如果我是查看您在此处发布的方法的开发人员,我根本不明白我有可能发送嵌套数据。

    我将对对象“org”的 Products 集合进行迭代并将它们添加到他们的 EF 集合中,然后稍后将 Organization 添加到它自己的集合中。

    然后,显然是 SaveChanges()。

    这将清楚地区分这个接受嵌套对象的方法,与另一个不接受嵌套对象的方法,只是简单地保存我的新空组织。

    【讨论】:

    • 如果你不使用延迟加载,这可能是必要的,我就是这样。
    • 延迟加载与读取数据有关,从您的问题我了解到您对保存数据有疑问。
    猜你喜欢
    • 2019-02-14
    • 2016-08-27
    • 1970-01-01
    • 2014-01-08
    • 2015-03-22
    • 2015-09-05
    • 2013-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多