Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在服务层更新模型,而不读取MVVM中的整个实体_C#_Asp.net_Entity Framework_Design Patterns_Viewmodel - Fatal编程技术网

C# 在服务层更新模型,而不读取MVVM中的整个实体

C# 在服务层更新模型,而不读取MVVM中的整个实体,c#,asp.net,entity-framework,design-patterns,viewmodel,C#,Asp.net,Entity Framework,Design Patterns,Viewmodel,众所周知,服务层负责更新,当然还有读取、写入和删除模型,或者我可以称之为实体。让我们暂时忽略存储库层,因为我不喜欢它,它只是隐藏了很多实体框架特性 设计良好的系统中的数据流应为: Service (model) <<<-->>> Controller (mapping Model <-> ViewModel) 为了能够通过上述数据流更新数据库中的模型,我必须将整个模型从数据库读取到服务,再读取到控制器,并使用AutoMapper(例如)将我从Vi

众所周知,服务层负责更新,当然还有读取、写入和删除模型,或者我可以称之为实体。让我们暂时忽略存储库层,因为我不喜欢它,它只是隐藏了很多实体框架特性

设计良好的系统中的数据流应为:

Service (model) <<<-->>> Controller (mapping Model <-> ViewModel)
为了能够通过上述数据流更新数据库中的模型,我必须将整个模型从数据库读取到服务,再读取到控制器,并使用AutoMapper(例如)将我从ViewModel获得的数据映射到模型。现在,我们有了一些更改值的旧模型。现在,我可以将编辑后的模型传递回服务,并执行DbContext.UpdateModel

其缺点是:

我们必须发出额外的读取查询来读取整个模型,否则,DbContext.UpdateModel将把none-mapped属性保留为默认值

此外,已经为整个模型生成了更新查询,尽管我可能只更改了模型的一小部分

我有时发现设计模式迫使隐藏许多特性,这可能会使程序更高效


有没有什么方法,比如说设计模式或对服务模式的任何编辑,我可以将ViewModel映射到模型,并将模型传递到服务,只更新映射的属性,这样在映射属性之前就不需要阅读整个实体?

我的回答可能有点离题,但我还是要发布它,因为我觉得我想说的是一个比较宽泛的话题

你说

众所周知,服务层负责更新,当然还有读取、写入和删除模型,或者我可以称之为实体

问题是,服务层实际上不应该这样使用。我的意思是-你根本不应该有所谓的服务。你所描述的被称为。它是实体和服务的组合,实体是简单的数据结构而不是合适的对象!和服务用于在实体上执行操作

用马丁·福勒的话来说

[…]有一组服务对象,它们捕获所有域逻辑,执行所有计算并使用结果更新模型对象。这些服务位于域模型之上,并使用域模型来处理数据

这很糟糕

在一个对象内组合方法和数据。那么您将要寻找的是工作单元设计模式。事实上,实体框架已经实现了这个模式。至于使用EF实现这种富对象方法,或者实际上使用任何可以在.NET中使用的ORM,我推荐Vaughn Vernon的文章。不可能总结这篇文章的全部内容,但为了避免只使用链接,答案是:基本上,沃恩提出了两种方法:使用实现类和域对象创建分离的接口,域对象由他称之为状态对象的东西进行备份

针对评论: 基本上是的-建议是将数据和方法结合在一起,而不是有一个所谓的实体,在大多数情况下,这个实体是仅用于从DB获取数据的简单数据结构,还有一个单独的类,称为service,它对实体执行操作

这可能是个好主意,也很有趣,但这仍然是理论上的,对吗?第二个环节是将这种方法付诸实施。当然,当您开始重构代码时,您必须问自己一个问题:如何将我的富对象存储在数据库中?我的意思是-这的全部目的是在对象中封装业务域逻辑,而不必处理所有这些技术混乱。我们的目标是尽可能地实现纯C对象的含义——尽可能减少依赖性。我们来举个例子。假设您有订单和产品类

使用富域模型,您将拥有这样的类

[Table("orders")]
class Order
{
    [Key]
    public int Id { get; set; }
    public List<Product> Products { get; set; }

    public bool AddProduct(Product product)
    {
        if(this.Products.Contains(product))
        {
            return false;
        }

        order.Products.Add(product);

        return true;
    }

}
注意两件事: 1.我们将技术人员转移到控制器,并将业务逻辑封装在Order类中,让我们假设ifthis.Products.Containsproduct是我们唯一的业务规则[好东西] 1.Order类应该只包含与业务相关的内容。当涉及到阅读和理解这个类时,特定于ORM的注释只会引入技术噪音,更不用说我们的模型中有不必要的依赖项[坏事]

沃恩讨论了两种处理方法。您可以使用业务方法提取分离的接口

interface IOrder
{
    bool AddProduct(Product product);
}
然后在类中实现它,如类顺序:IOrder。链接的博客文章指出了这种解决方案的缺点

普适语言并没有通过使用诸如IPProduct、IBacklogItem等接口得到真正的加强。IPProduct和IBacklogItem不在我们的普适语言中,但Product和BacklogItem是。因此,面向客户机的名称应该是Product、BacklogItem和t 他喜欢。我们可以通过简单地命名接口产品、BacklogItem、Release和Sprint来实现这一点,但这意味着我们必须为实现类提供合理的名称。让我们暂停一下,继续讨论第二个相关问题

确实没有很好的理由创建一个分离的接口。我们不太可能创建两个或多个IPProduct或任何其他接口的实现。我们创建一个独立接口的最好理由是当可能存在或存在多个实现时,而这在这个核心领域是不会发生的

另一个解决方案是创建两个对象——一个仅用于业务逻辑,另一个负责更改跟踪并用于与数据库通信。使用这种方法,您就拥有了业务对象,而没有任何与业务角度细节无关的迹象。正如沃恩总结的那样

最终,我们的目标是远离实体框架


这真是一个宽泛的话题。很难用如此时尚的方式来解释它——关于这个话题有很多书;——。一般来说,我建议你读弗农的书,书名是。这是关于DDD的,但它也展示了如何编写正确的面向对象代码。

感谢您的回答,所以您建议将EF的直接调用从服务中隔离到单独的类存储库,以避免使用反模式?我还没有检查那个推荐的链接,但一般来说这是对的吗?这并不是真的要将EF调用放入存储库。我的建议是将方法从服务移动到对象。您可以在存储库中引入诸如Getint primaryKey或UpdateEntityToUpdate之类的方法,但这并不是我建议进行更改的主要原因。检查提供的链接-你可以找到比我在这里提供的更精确和更广泛的解释:-我会的,如果有不清楚的地方,我会给你回复-如果可以的话。谢谢。当然,没问题——我会尽我所知回答任何问题!我更新了一点我的答案-我希望这将澄清你的一些疑虑。如果还有任何问题,请随时提问!
[Table("orders")]
class Order
{
    [Key]
    public int Id { get; set; }
    public List<Product> Products { get; set; }

    public bool AddProduct(Product product)
    {
        if(this.Products.Contains(product))
        {
            return false;
        }

        order.Products.Add(product);

        return true;
    }

}
class OrderController
{
    public ActionResult AddProduct(int orderId, int productId){
        Order order = this.orderRepository.FirstOrDefault(orderId);
        Product product = this.productRepository.FirstOrDefault(productId);

        bool productAdded = order.AddProduct(product);

        // do something else
    }
}
interface IOrder
{
    bool AddProduct(Product product);
}