C# 在MVC控制器中使用命令-查询分离原则

C# 在MVC控制器中使用命令-查询分离原则,c#,asp.net-mvc,command-query-separation,C#,Asp.net Mvc,Command Query Separation,我喜欢的想法,但不知道如何在添加实体的MVC控制器操作中使用它,并且在添加实体后需要新实体的ID 例如,在下面的简化示例中,服务用于创建新项目: public ActionResult Assign(AssignViewModel viewModel) { var newItem = _AssignItemService.AssignItem(viewModel.ItemName, viewModel.ItemValue); return RedirectToAction(

我喜欢的想法,但不知道如何在添加实体的MVC控制器操作中使用它,并且在添加实体后需要新实体的ID

例如,在下面的简化示例中,服务用于创建新项目:

public ActionResult Assign(AssignViewModel viewModel)
{
     var newItem = _AssignItemService.AssignItem(viewModel.ItemName, viewModel.ItemValue);

     return RedirectToAction("ListItem", new {id = newItem.Id);
}
但是,当我重定向到要显示新项的操作时,我需要知道新创建项的ID,以便可以从数据库中检索它。因此,我必须要求服务返回新创建的项目(或者至少返回其ID)

在纯CQS中,命令没有返回值,因此上面的模式将无效


感谢您的建议。

我认为您的观点太迂腐了

当您想向数据库询问一个问题时,例如“密西西比河以西有多少客户在6月份购买了红色物品?”这是一个查询。在插入过程中返回ID本身并不是一个典型的查询

与软件开发中的大多数其他事情一样,这种模式不是绝对的。甚至福勒也表示,他愿意在方便的时候打破它:

弹出堆栈是修改状态的修改器的一个很好的示例。 Meyer正确地说,您可以避免使用这种方法,但事实并非如此 一个有用的成语。所以我宁愿在可能的时候遵循这个原则,但是 我准备打破它去拿我的爸爸


如果您确实希望从数据库中检索最近添加的ID,而不是将其插入数据库中,则可以使用以下方法。但我认为您增加复杂性并不是为了获得额外的好处。

您应该将从viewmodel的值创建的“项”(或您实体的名称)的实例传递给
AssignItem
方法,然后该方法不必返回任何内容,相反,它将只更新实体的Id属性,使其成为命令方法


然后,您可以将entity.Id用于任何您想要的内容,方法是让调用方指定新实体的Id(这很可能意味着使用guid作为键)


但是,根据我的经验,强制执行命令可能不会返回结果的(纯粹主义)规则只会带来一些问题。

此外,如果使用范围标识或类似标识,请确保正确处理多线程情况。例如
T1
插入,
T2
插入,
T1
T2
s插入中获取
Id
T2
获取相同的Id。当然,同样的问题也适用于任何原子操作/事务,所以我相信您已经考虑过了。让数据库通过insert函数的返回值将ID传递给您的另一个好理由。我认为Fowler的评论考虑到堆栈中的pop方法是可以的,因为它的使用是通用的,所以它已经成为所有开发人员的习惯用法,但是我不认为从保存方法返回ID是一个习惯用法。我同意你的观点,虽然没有什么是绝对的,偶尔打破这种规则也没什么大不了的while@jorgehmv:这将是一个insert方法,从数据库返回一个ID是一个非常常见且非常容易理解的习惯用法。@Robert ok,也许是,但是多年前,从方法返回错误代码也是一个很好的习惯用法,这不再是一个好的实践,以后如何检索“item”?传递给AssignItem方法的对象在返回后包含Id信息。由于该方法是一个命令,因此可以更改对象的状态。在这一点上,您基本上还没有返回值吗?当然,它不是从函数的后面出来的,但是您仍然返回一个值,您只是将返回值推到其他地方。也就是说,我喜欢将ID保存在对象中,而不是单独返回。这种差异是为什么命令-查询分离在大多数情况下都是一个好主意的主要原因。如果您多次使用相同的参数调用相同的方法,那么每次都会返回不同的东西,这很奇怪。相反,如果您一次又一次地传递同一对象,它将始终不返回任何内容,并且仅在必要时更改对象的状态(通常只是第一次,因为这是db插入),您将永远不会传递同一对象进行两次插入。方法每次都返回不同的结果是经过设计的;每个新ID都必须是唯一的,以区别于其他ID。谢谢erikkallen。这是有道理的,但最终我认为jorgehmv的想法会对我更有效。