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);
}