gpt4 book ai didi

c# - 如何跟踪上次对DDD中的对象进行更改的用户?

转载 作者:太空狗 更新时间:2023-10-30 01:07:18 24 4
gpt4 key购买 nike

我正在尝试实施DDD,并觉得我掌握了它的窍门,但我也有一些问题。
在90%的域对象中,我想知道最后一个对其进行更改的用户。我不需要一个完整的审计跟踪-这对我的需要是过分的。
我的所有类都实现了一个抽象基类,其中包含:

    public abstract class Base
{
public User LastChangedBy { get; set; }
public DateTime LastChangedDate { get; set; }
}

选择1:遵循DDD原则,但不那么优雅
从不让对象进入无效状态
public abstract class Base
{
public User LastChangedBy { get; protected set; }
public DateTime LastChangedDate { get; protected set; }
}

public SomeObject
{
.....
SomeBehaviorThatChangesObject(User changedBy, ...)
AnotherBehaviorThatChangesObject(User changedBy, ...)
}

我必须把所有的setter设为私有,把基类setter设为protected。对对象所做的每一个更改都需要通过一个将(用户changedby)作为参数的方法来完成。
非常安全,但是由于用户可能对对象做6个更改,所以我必须为每个更改提供用户对象。实际上,我必须为我的域模型中的几乎所有方法提供这个…
选择2:不是最好的,但我读过
引入bool isvalid字段。在所有setter中,我都将isvalid设置为false。创建了将此字段设置为true的方法acceptchanges(用户changesacceptedby)。记住,在持久化对象之前,一定要检查它是否有效。
public abstract class Base
{
public bool IsValid {get; protected set;}
public User LastChangedBy { get; protected set; }
public DateTime LastChangedDate { get; protected set; }
}

public SomeObject
{
public Object Propery{get; set{IsValid = false; ...}}
.....
SomeBehaviorThatChangesObject(...)
{
//change the object
IsValid = false;
}
}

选择3:我的眼睛最实用,但不是很DDD
在UnitOfWork的持久层或repository.saveChanges之类的存储库(用户更改)中执行此操作。我,或者不管是谁实现了这一部分,都可能忘记这一点,这会使对象处于无效状态…
public SomeRepository
{
public void Update (User changedBy)
{...}
}

能够看到谁最后更改了一个实体是很正常的,但是我还没有看到它实现ddd的任何好例子。你怎么做到的?
更新
针对Jgauffins解决方案:
谢谢,base实际上实现了一个接口,我简化了很多,以避免信息过载。我觉得这并不优雅,因为每一个方法都需要我的用户对象作为每次更改的参数,而我突然不得不将所有的setter绝对私有化…
把它放在回购协议中可以完成这项工作,但上面的论点是有效的,我还没有想到这一点,所以这正是我问的原因。实际上,我正在计划一个可能需要更改某些对象的服务。
这是一个巨大的变化,改变了数百种方法和特性,所以我想成为舒尔。同时,我也会使用很多方法来设置一个字段,就像我在 this post中提到的,在这里我不需要一个方法,因为“set”描述的足够让用户知道更改的作用……我的直觉告诉我你是对的,只是想看看是否有其他方法可以做同样的事情。
最终更新:
阅读了所有的评论、问题和建议的解决方案,我意识到我可能不得不重新考虑如何看待lastchangedby和lastchangeddate字段。对于某些对象,这实际上与我认为属于该领域的某些东西有关。对许多其他人来说,我要找的是真正的审计。我不知道有什么不同。
也就是说,文档对象可以由创建者以外的人更改,这将有助于某些行为(通知创建者等)。在这些情况下,我感兴趣的并不是最后一个更改文档对象的人,而是最后一个编辑文档内容的人。
而不是将此与LastChangedBy混合,我为LististDeDy创建字段。如果我需要跟踪每一个更改,这甚至可以是一个编辑器列表。
当然,大多数情况下,这与lastchangedby是同一个用户,但是看看创建者进入并更改属性以锁定文档以进行进一步编辑的场景。然后文档并没有真正被编辑,而是被更改了,而且出于审计原因,我想跟踪一些内容。如果我使用同一字段来跟踪编辑,那就错了。我可以这么做,因为现在的要求是创建者可以进去看看上次是谁修改了文档,但这并不是真正正确的解决方案。
为了实施审计,我做了以下工作:
首先,我将基类划分为需要实现的接口。lastchangedby和lastchangeddate是在iauditable接口中定义的,需要审计的对象必须实现这个接口。
然后重写dbcontext.saveChanges(),如下所示:
        public override int SaveChanges()
{
if(ChangeTracker.Entries<IAuditable>().Any())
throw new InvalidOperationException
(
"Tried to save changes on an object that is needs to be Audited. Please provide the User that makes the changes!"
);
return base.SaveChanges();
}

public int SaveChanges(User changedBy)
{
var entries = ChangeTracker.Entries<IAuditable>().Where(entry=>entry.State == EntityState.Modified);
foreach (var dbEntityEntry in entries)
{
dbEntityEntry.Entity.Audit(DateTime.Now, changedBy);
}
return base.SaveChanges();
}

当然还有其他方法可以做到这一点,但这似乎至少是一个开始。
现在,我意识到我的问题本可以更好,但老实说,我没有意识到问题的一部分是我想跟踪不同对象上由于不同原因而发生的变化。上面文档的示例只是其中一个对象,其中lastchangedby实际上不是我需要在我的域中设置或跟踪的对象,但它可以被重写为像上面这样更具体。

最佳答案

我从Thread.CurrentPrincipal开始。但是如果以后要切换到异步处理(例如使用我描述的here命令),就不可能使用Thread.CurrentPrincipal
但首先有一个根本问题:

public abstract class Base
{
public User LastChangedBy { get; protected set; }
public DateTime LastChangedDate { get; protected set; }
}

那不是基类。它没有添加任何功能。您应该改为使用一个名为 ITrackChanges或类似的接口。
public SomeObject
{
.....
SomeBehaviorThatChangesObject(User changedBy, ...)
AnotherBehaviorThatChangesObject(User changedBy, ...)
}

我就是这样做事的。你为什么认为它不优雅?管理员或后台服务可以使用该方法代表用户执行操作。
更新
我觉得它并不优雅,因为每个方法都需要我的用户对象作为每次更改的参数
好。这是商业需求,对吧?必须更改 LastChangedBy属性。因此必须提供。
在DDD中不禁止公共设置者。您可以使用它们,但在这种情况下,每次更改都必须更新 LastChangedByLastChangedDate。这个逻辑应该由模型本身来执行,而不是由调用代码来执行。因此,不可能使用公共setter。

关于c# - 如何跟踪上次对DDD中的对象进行更改的用户?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13040380/

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