当前位置: 首页 > news >正文

网站百度关键词排名软件xampp里wordpress安装教程

网站百度关键词排名软件,xampp里wordpress安装教程,江夏区做网站,如需手机网站建设原文链接#xff1a;https://enterprisecraftsmanship.com/posts/ddd-bulk-operations/将批量操作与领域驱动设计相结合是一个困难的问题。在这篇文章中#xff0c;我们将看看为什么会这样#xff0c;并讨论如何结合两个。本文也是对读者提问的回应。这个问题包含一个有趣的… 原文链接https://enterprisecraftsmanship.com/posts/ddd-bulk-operations/将批量操作与领域驱动设计相结合是一个困难的问题。在这篇文章中我们将看看为什么会这样并讨论如何结合两个。本文也是对读者提问的回应。这个问题包含一个有趣的例子我将在本文中使用Hi Vladimir!你有关于DDD环境下批量操作的文章吗我没有发现任何有用的东西。请考虑以下示例给定一个任务列表我想为所有与所选月份和类别匹配的任务设置一个执行日期另外我不能为已经完成的任务设置执行日期对于给定的月份和类别最多可以有30000个任务。目前我创建了一个SetExecutionDateDomainService查询tasksRepository.GetBy(month, category)对于每个任务检查task.CanSetExecutionDate()如果为true则调用taskRepository.Update(task)。关于如何处理这个问题有什么意见/建议吗有三种方法可以处理此问题逐个处理对象问题作者的处理方式依赖SQL批量更新结合使用规约和命令模式。前两种选择有权衡。我特别喜欢第三个。顺序处理处理此问题最直接的方法是检索所有合适的对象然后依次更新它们public class Task {public int Month { get; private set; }public string Category { get; private set; }public bool IsCompleted { get; private set; }public DateTime? ExecutionDate { get; private set; }public bool CanSetExecutionDate(){return IsCompleted  false;}public void SetExecutionDate(DateTime executionDate){Guard.Require(CanSetExecutionDate(), CanSetExecutionDate());ExecutionDate  executionDate;} }public class SetExecutionDateService {public void SetExecutionDate(int month, string category, DateTime executionDate){IReadOnlyListTask tasks  _repository.GetBy(month, category);foreach (Task task in tasks){if (task.CanSetExecutionDate()){task.SetExecutionDate(executionDate);_repository.Update(task);}}} } 该解决方案的主要优点是所有领域知识都包含在领域模型中。具体来说执行日期何时可以设置的知识CanSetExecutionDate方法。这里的缺点是缺乏性能单独处理和更新任务需要大量的数据库往返——每次更新一次。在OLTP类型的操作少量数据的事务处理之外DDD通常不能很好地工作。对于批量更新大量任务的用例也是如此——它不属于DDD的“舒适区”。批量操作或批量更新是在一次数据库往返中更新大量数据。使用原始SQL如果DDD不能很好地与批量更新配合使用那该怎么办这就是原始SQL的闪光点。SQL专门设计用于处理大量相关数据我们也可以将其用于我们的场景UPDATE dbo.Task SET ExecutionDate  ExecutionDate WHERECategory  Category ANDMonth  Month ANDIsCompleted  0 -- 领域知识重复 这种方法既快速又简单但违反了DRY原则您必须将哪些任务有资格设置执行日期的知识同时放到SQLIsCompleted0行和应用程序代码CanSetExecutionDate方法中。使用原始SQL可能不是一个坏的选择特别是在简单的项目中但是有更好的方法。使用规约模式简而言之规约模式 是关于将一段领域知识封装到单个单元称为规约中然后在三种场景中重用该单元数据检索内存验证创建新对象下图中的“按顺序施工”。我还写过虽然这个模式的想法看起来很有趣但它与CQRS模式相反因此应该被丢弃。原因是CQRS提供了另一个好处——松耦合在绝大多数情况下比DRY更重要。CQRS通过将单个统一模型拆分为两个来实现松耦合一个用于读取数据检索原始SQL查询的范围另一个用于写入内存验证DDD的范围。这种分离就是矛盾所在规约模式主张保持统一的模型。那么规约模式如何在批量更新的场景中提供帮助呢事实证明您不仅可以使用规约来查询数据库还可以更新数据库。首先让我展示这个模式的一个典型用法。然后我将演示如何为批量更新用例扩展它。在上述设置任务执行日期的用例中我们需要以下三个规约public sealed class TaskIsCompletedSpecification : SpecificationTask {public override ExpressionFuncTask, bool ToExpression(){return task  task.IsCompleted;} }public sealed class TaskMonthSpecification : SpecificationTask {private readonly int _month;public TaskMonthSpecification(int month){_month  month;}public override ExpressionFuncTask, bool ToExpression(){return task  task.Month  _month;} }//  TaskCategorySpecification, which is the same as TaskMonthSpecification 您可以在此GitHub仓储中找到基本Specification类和所有其他支持类的源代码。根据这些规约Task如下所示public class Task {public int Month { get; private set; }public string Category { get; private set; }public bool IsCompleted { get; private set; }public DateTime? ExecutionDate { get; private set; }public bool CanSetExecutionDate(){var spec  new TaskIsCompletedSpecification(); 1return spec.IsSatisfiedBy(this)  false;      1}public void SetExecutionDate(DateTime executionDate){Guard.Require(CanSetExecutionDate(), CanSetExecutionDate());ExecutionDate  executionDate;} } 请注意1中TaskIsCompletedSpecification的使用。它看起来可能是多余的毕竟此规约检查同一任务实例的IsCompleted字段但在应用程序中分配域知识时保持一致是很重要的。一旦您引入了一个规约来保存一部分知识所有其他类也应该开始使用它来遵守DRY原则。以下是领域服务public class SetExecutionDateService {public void SetExecutionDate(int month, string category, DateTime executionDate){var monthSpec  new TaskMonthSpecification(month);var categorySpec  new TaskCategorySpecification(category);var isNotCompletedSpec  new TaskIsCompletedSpecification().Not();SpecificationTask spec  monthSpec.And(categorySpec).And(isNotCompletedSpec); 1IReadOnlyListTask tasks  _repository.GetList(spec); 2foreach (Task task in tasks){if (task.CanSetExecutionDate()){task.SetExecutionDate(executionDate);_repository.Update(task);}}} } 领域服务组合了三个规约第1行并将它们传递给仓储“2”。仓储如下所示我使用的是NHibernate但实体框架的代码是相同的public IReadOnlyListTask GetList(SpecificationTask specification) {return _session.QueryTask().Where(specification.ToExpression()).ToList(); } 这段代码依赖于复杂的ORM功能它遍历规约的表达式树并将其转换为SQL。例如此组合规约var monthSpec  new TaskMonthSpecification(month); var categorySpec  new TaskCategorySpecification(category); var isNotCompletedSpec  new TaskIsCompletedSpecification().Not(); SpecificationTask spec  monthSpec.And(categorySpec).And(isNotCompletedSpec); 被翻译成Month  Month AND Category  Category AND NOT(IsCompleted  1) C#表达式与ORM的结合是一对强大的组合。但即使是他们也只能带你走这么远。ORMs允许您使用表达式来查询数据库但不能更新它。为了实现批量更新功能将执行日期设置为一次数据库往返中的所有任务我们需要更新数据库。那么该怎么办呢好消息是使用规约模式处理数据库不必依赖ORMs或C#表达式。表达式树是一个方便的工具可以简化规约的实现但它们只是这样一个工具。另一个工具是原始SQL本身。实际上您可以将这两种方法结合起来使用表达式树进行内存验证和查询数据库使用原始SQL进行批量更新。其思想是除了ToExpression方法外每个规约还必须实现ToSql以便为updatesql查询生成适当的过滤器。下面是基本规约类的外观同样请查看GitHub仓储以获取完整的源代码public abstract class SpecificationT {public bool IsSatisfiedBy(T entity){FuncT, bool predicate  ToExpression().Compile();return predicate(entity);}public abstract ExpressionFuncT, bool ToExpression();/* And(), Or(), Not() methods */ } 您需要添加两个新的抽象方法public abstract string ToSql(); public abstract IEnumerableSqlParameter ToSqlParameters(); ToSql将规约转换为SQLToSqlParameters为该SQL提供必需的参数。现在您需要在所有规约子类中实现这两个方法。举个例子public sealed class TaskMonthSpecification : SpecificationTask {private readonly int _month;public TaskMonthSpecification(int month){_month  month;}public override ExpressionFuncTask, bool ToExpression(){return task  task.Month  _month;}public override string ToSql(){return [Month]  Month;}public override IEnumerableSqlParameter ToSqlParameters(){yield return new SqlParameter(Month, _month);} } 最后批量更新是这样的// Domain service public void SetExecutionDate(int month, string category, DateTime executionDate) {var monthSpec  new TaskMonthSpecification(month);var categorySpec  new TaskCategorySpecification(category);var isNotCompletedSpec  new TaskIsCompletedSpecification().Not();SpecificationTask spec  monthSpec.And(categorySpec).And(isNotCompletedSpec);_repository.UpdateExecutionDate(executionDate, spec); }// TaskRepository public void UpdateExecutionDate(DateTime executionDate, SpecificationTask specification) {string sql  UPDATE dbo.TaskSET ExecutionDate  ExecutionDateWHERE   specification.ToSql();using (DbCommand command  _session.Connection.CreateCommand()){command.CommandText  sql;command.Parameters.AddRange(specification.ToSqlParameters().ToArray());command.Parameters.Add(new SqlParameter(ExecutionDate, executionDate));command.ExecuteNonQuery();} } 这种规约模式的使用带来了第四种场景批量更新注意这个用例并不与CQRS相矛盾用于内存验证和批量更新的领域知识的重用发生在应用程序的写部分。因此我想收回我先前的说法即规约只在简单的场景中有用在这种场景中松耦合并不是那么重要。批量更新是这种模式的一个非常有效的用例这种用例可以出现在任何复杂的应用程序中。在上述实现中有关如何为批量更新选择任务的业务需求都位于域层。这些要求是三个前提条件的组合所有这些条件都包含在规约中特定月份的任务具有特定类别的任务未完成的任务。那么问题解决了还没有。虽然我们已经封装了哪些任务适合更新的知识但更新本身仍然分散在Task领域类和TaskRepository之间1和2public class Task {/* Month, Category, IsCompleted, ExecutionDate properties */public bool CanSetExecutionDate(){var spec  new TaskIsCompletedSpecification();return spec.IsSatisfiedBy(this)  false;}public void SetExecutionDate(DateTime executionDate){Guard.Require(CanSetExecutionDate(), CanSetExecutionDate());ExecutionDate  executionDate; 1} }// TaskRepository public void UpdateExecutionDate(DateTime executionDate, SpecificationTask specification) {string sql  UPDATE dbo.TaskSET ExecutionDate  ExecutionDate  2WHERE   specification.ToSql();using (DbCommand command  _session.Connection.CreateCommand()){command.CommandText  sql;command.Parameters.AddRange(specification.ToSqlParameters().ToArray());command.Parameters.Add(new SqlParameter(ExecutionDate, executionDate));command.ExecuteNonQuery();} } 这是领域逻辑重复的另一个实例。为了解决这个问题我们需要另一块拼图命令模式。遇见命令模式上面清单中的重复似乎不是什么大事因为它只是一个字段的赋值。但事实上这是一件大事 — 还有一个先决条件要求任务不能完成才能有执行日期public void SetExecutionDate(DateTime executionDate) {/* 此前提条件是执行日期分配的固有部分 */Guard.Require(CanSetExecutionDate(), CanSetExecutionDate());ExecutionDate  executionDate; } 设置执行日期的行为是整个SetExecutionDate方法而不仅仅是其中的赋值操作。该方法的前提条件也存在于SQL查询TaskRepository生成的UPDATE dbo.Task SET ExecutionDate  ExecutionDate WHERE [Month]  MonthAND Category  CategoryAND NOT(IsCompleted  1) -- 前提条件 问题是没有任何东西可以阻止TaskRepository在未查询此前提条件的情况下设置执行日期。IsCompleted和ExecutionDate字段之间的连接是一项重要的领域知识您必须记住这一点并在Task和TaskRepository中复制它们。想象一下不必指定DateTime这样的基本类型而必须指定一个包含多个字段的值对象。让Task和TaskRepository中的逻辑不同步变得非常容易。那么如何克服这个问题避免赋值逻辑的重复呢这就是命令模式发挥作用的地方。命令模式本质上与规约的作用相同但是命令不检查领域对象的属性而是更改这些属性。您可以将这两种模式之间的差异想象为规约模式封装了要更新哪些数据的知识。命令模式封装了如何更新数据的知识。另外虽然您可以在4种场景中使用规约但命令仅在两种情况下有用内存更新和批量更新。Command基类的如下:public abstract class CommandT {/* 先决条件之外的限制 */protected readonly IReadOnlyListSpecificationT _restrictions;  1protected Command(IReadOnlyListSpecificationT restrictions){_restrictions  restrictions;}/* Commands 前提条件 */protected abstract IEnumerableSpecificationT GetPreconditions();  2private SpecificationT CombinedSpecification GetPreconditions().Concat(_restrictions).Aggregate(SpecificationT.All, (x, y)  x.And(y));protected abstract void ExecuteCore(T entity);protected abstract string GetTableName();protected abstract string ToSqlCore();protected abstract IEnumerableSqlParameter ToSqlParametersCore();/* 内存更新 */public bool CanExecute(T entity){return CombinedSpecification.IsSatisfiedBy(entity);}public void Execute(T entity){if (CanExecute(entity)  false)throw new InvalidOperationException();ExecuteCore(entity);}/* 用于批量更新的SQL */public string ToSql(){return UPDATE   GetTableName()  SET   ToSqlCore()  WHERE   CombinedSpecification.ToSql();}/* 用于批量更新的SQL参数 */public IReadOnlyListSqlParameter ToSqlParameters(){return CombinedSpecification.ToSqlParameters().Concat(ToSqlParametersCore()).ToArray();} } 这个类看起来有点大但背后的想法很简单 — 将前提条件放到命令中这样就连省略这些前提条件的选项都没有了。除了先决条件第2行之外还可以对命令施加其他限制“1”。下面是我们的批量更新Commandpublic class SetExecutionDateCommand : CommandTask {private readonly DateTime _executionDate;public SetExecutionDateCommand(DateTime executionDate, params SpecificationTask[] restrictions): base(restrictions){_executionDate  executionDate;}protected override IEnumerableSpecificationTask GetPreconditions(){yield return new TaskIsCompletedSpecification().Not();}protected override void ExecuteCore(Task entity){entity.ExecutionDate  _executionDate;}protected override string GetTableName(){return dbo.Task;}protected override string ToSqlCore(){return ExecutionDate  ExecutionDate;}protected override IEnumerableSqlParameter ToSqlParametersCore(){yield return new SqlParameter(ExecutionDate, _executionDate);} } 用法如下// SetExecutionDateService public void SetExecutionDate(int month, string category, DateTime executionDate) {var monthSpec  new TaskMonthSpecification(month);          1var categorySpec  new TaskCategorySpecification(category); 1var command  new SetExecutionDateCommand(executionDate, monthSpec, categorySpec);_repository.BulkUpdate(command); }// TaskRepository public void BulkUpdate(SetExecutionDateCommand command) {using (DbCommand dbCommand  _session.Connection.CreateCommand()){dbCommand.CommandText  command.ToSql();dbCommand.Parameters.AddRange(command.ToSqlParameters().ToArray());dbCommand.ExecuteNonQuery();} } 请注意规约限制1是可选的您可以将它们应用于命令也可以不应用于命令但规约前提条件是必需的。事实上您甚至没有指定该前提条件的选项 — 它被放到命令本身中。这就是封装的本质你不能总是相信自己会做正确的事情你必须消除做错事的可能性。另外请注意我不熟悉应用程序的细节并假设月份和类别限制是可选的。如果不是您也应该将它们移到GetPreconditions方法在这种情况下命令和领服务将变得更加简单public class SetExecutionDateCommand : CommandTask {private readonly DateTime _executionDate;private readonly int _month;private readonly string _category;public SetExecutionDateCommand(DateTime executionDate, int month, string category): base(new SpecificationTask[0]){_category  category;_month  month;_executionDate  executionDate;}protected override IEnumerableSpecificationTask GetPreconditions(){yield return new TaskIsCompletedSpecification().Not();yield return new TaskMonthSpecification(_month);yield return new TaskCategorySpecification(_category);}/* 剩下的一样 */ }// SetExecutionDateService public void SetExecutionDate(int month, string category, DateTime executionDate) {var command  new SetExecutionDateCommand(executionDate, month, category);_repository.BulkUpdate(command); } 同样由于其简单性原始SQL可能仍然是大多数项目的更好选择即使它不遵守 DRY 原则。但是规约和命令模式的组合对于具有复杂域逻辑的项目可能很有用您希望在内存中更新和批量更新之间重用这些逻辑。总结DDD适合于事务处理少量数据OLTP不能很好地处理批量操作。批量操作或批量更新是在一次数据库往返中更新大量数据。有三种方法可以处理批量更新顺序处理遵循干燥原则不利于性能使用原始SQL有利于性能违反了DRY原则结合使用规约和命令模式坚持DRY和良好的性能。除了内存验证、查询数据库和创建新对象之外批量操作是规约模式的第四个用例。规约模式封装了要更新哪些数据的知识。命令模式封装了如何更新数据的知识。这两种模式都允许您在领域模型和批量操作之间重用这些知识。命令使用规约作为内存更新批量更新。欢迎关注我的个人公众号”My IO“
http://www.zqtcl.cn/news/397697/

相关文章:

  • 杭州网站设计建立企业网站专业做电脑系统下载网站好
  • 哈尔滨建设网站成本网站建设无广告
  • 发布网站搭建教程云排名网站
  • 无锡大型网站建设房地产景区网站建设方案
  • 自学网站建设工资公众号怎么开通直播功能
  • 网站建设上市公司wordpress park主题
  • 百度网站建设一年多少钱奇艺广州网站建设 熊掌号
  • 建设网站怎么收费标准网站和自媒体都可以做
  • 网站自己怎么做无锡常规网络营销是什么
  • 活泼风格的网站crm免费客户管理系统
  • 网站系统发生错误百度seo灰色词排名代发
  • 免费做名片儿的网站wordpress grace6
  • 有关网站开发的创意四川工程造价信息网官网
  • 网站目录结构北京注册公司地址可以是住宅吗
  • 龙信建设集团网站傻瓜式建站软件下载
  • 在360做网站和百度做网站的区别什么是网站地址
  • 营销型的物流网站模板下载长江设计公司
  • 网站程序制作购买网站域名
  • 网站建设中html下载如何用社交网站开发客户
  • 开设购物网站的方案政务公开和网站建设情况
  • 一台云服务器做多个网站营销型网站的建设重点是什么
  • 泉港网站建设推广服务公司电子商务好就业吗
  • 自己做网站开发如何找客户wordpress 显示 子分类
  • 腾讯邮箱网页版登录宿迁seo公司
  • 网站建设找盖亚科技WordPress 百度 主动
  • 中国最受欢迎的网站杭州做电商网站
  • 百度招聘 网站开发全网营销实战培训
  • 备案网站内容说明广州哪个区封了
  • 大足建网站的软件开发者模式怎么打开
  • 中国有什么网站做跨境零售农商1号的网站建设费