gpt4 book ai didi

c# - C#中的@Transactional等效项和DDD应用程序服务的并发性

转载 作者:太空宇宙 更新时间:2023-11-03 17:52:37 24 4
gpt4 key购买 nike

我正在阅读Vaughn Vernon的有关实现域驱动设计的书。我也一直在通过book code, C# version, from his github here

本书的Java版本具有装饰器@Transactional,我认为它们来自spring框架。

public class ProductBacklogItemService
{
@Transactional
public void assignTeamMemberToTask(
string aTenantId,
string aBacklogItemId,
string aTaskId,
string aTeamMemberId)
{
BacklogItem backlogItem =
backlogItemRepository.backlogItemOfId(
new TenantId(aTenantId),
new BacklogItemId(aBacklogItemId));

Team ofTeam =
teamRepository.teamOfId(
backlogItem.tennantId(),
backlogItem.teamId());

backlogItem.assignTeamMemberToTask(
new TeamMemberId(aTeamMemberId),
ofTeam,
new TaskId(aTaskId));
}
}


在C#中等效的手动实现是什么?我在考虑以下方面:

public class ProductBacklogItemService
{
private static object lockForAssignTeamMemberToTask = new object();
private static object lockForOtherAppService = new object();

public voice AssignTeamMemberToTask(string aTenantId,
string aBacklogItemId,
string aTaskId,
string aTeamMemberId)
{
lock(lockForAssignTeamMemberToTask)
{
// application code as before
}
}

public voice OtherAppsService(string aTenantId)
{
lock(lockForOtherAppService)
{
// some other code
}
}
}


这给我留下了以下问题:


我们是按应用程序服务还是按存储库锁定?即我们不应该执行 backlogItemRepository.lock()吗?
当我们将多个存储库作为应用程序服务的一部分读取时,我们如何在交易过程中保护存储库之间的依赖关系(聚合根通过身份引用其他聚合根)–我们是否需要在存储库之间使用相互关联的锁?
是否有任何DDD基础架构框架可以处理任何此类锁定?


编辑

使用事务有两个有用的答案,因为我还没有选择我的持久层,而是使用内存中的存储库,它们是很原始的,所以我写了它们(它们不具有事务支持,因为我不知道如何加!)。

我将设计系统,因此无需同时对多个聚合根进行原子更改,但是我需要在多个存储库中进行一致读取(即,如果从多个其他聚合中引用了BacklogItemId,那么我们需要防止竞争情况(如果删除BacklogItemId)。

因此,我可以仅使用锁就可以摆脱困境,还是需要在内存存储库中添加TransactionScope支持?

最佳答案

TL; DR版本

您需要将代码包装在System.Transactions.TransactionScope中。注意多线程顺便说一句。

完整版本

因此,聚合的重点是定义一致性边界。这意味着任何更改都应导致聚合的状态仍然尊重其不变性。这不一定与交易相同。实际交易是跨领域的实现细节,因此可能应该这样实现。

关于锁定的警告

不要锁定。尝试忘记有关实现悲观锁定的任何想法。要构建可扩展的系统,您别无选择。数据需要花费时间并从磁盘到达屏幕的事实意味着您具有最终的一致性,因此应为此而构建。您不能真正防止出现这种竞争状况,您只需要考虑它们可能发生的事实,并能够警告“失败的”用户其命令失败。通常,您以后可以开始查找这些问题(几秒钟,几分钟,几小时,几天,几天,无论您的域专家告诉您SLA是什么),并告诉用户以便他们可以采取一些措施。

例如,假设有两个薪金职员在银行同时支付员工的费用。他们将在以后找出帐簿何时平衡,并采取一些补偿措施来纠正这种情况。您不想将薪资部门的规模缩减到一次工作的一个人,以避免这些(稀有)问题。

我的实施

我个人使用命令处理器样式,因此我所有的应用程序服务都实现为ICommandHandler<TCommand>CommandProcessor本身就是查找正确的处理程序并要求其处理命令的事物。这意味着CommandProcessor.Process(command)方法可以在System.Transactions.TransactionScope中处理其全部内容。

例:

public class CommandProcessor : ICommandProcessor
{
public void Process(Command command)
{
using (var transaction = new TransactionScope())
{
var handler = LookupHandler(command);
handler.Handle(command);

transaction.Complete();
}
}
}


您并没有采用这种方法,因此要使您的交易成为跨领域的关注点,您需要将其移到更高的级别。这高度依赖于您所使用的技术(ASP.NET,WCF等),因此,如果您添加更多细节,可能会很明显地放一些东西。

关于c# - C#中的@Transactional等效项和DDD应用程序服务的并发性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19973523/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com