asp.net 如何在存储库中的域模型上设置私有字段

piok6c0g  于 2023-10-21  发布在  .NET
关注(0)|答案(3)|浏览(95)

我目前正在使用一个使用贫血领域模型的代码库,我试图将更多的逻辑转移到领域模型中,以实现领域模型和领域驱动设计,但我正在努力解决以下问题。
我有一个名为Job的域模型,它看起来像这样,

public class Job
{
   private DateTime _someOtherDate;
   private DateTime _lastUpdated;

   // this may be called from many different services
   public void SetLastUpdated()
   {
     _lastUpdated = DateTime.UtcNow;
   }
}

在某个时间点,在处理作业的过程中,我想将作业的上次更新日期设置为该特定时间点。为了做到这一点,我已经为它创建了一个公共setter,正如你在上面看到的。
当我从存储库中的数据库中提取Job时,出现了一个问题,因为我现在没有这个字段的公共setter,因为我已经将其限制为SetLastUpdated()
有人能告诉我如何在检索作业时允许在存储库实现中设置此属性,而不是从仅限于调用SetLastUpdated()的服务中设置。

**更新1)**我已经更新了这个问题,因为使用开始日期是一个不好的例子。
**更新2)**从给出的答案来看,我能看到的唯一方法是在仓库中不使用AutoMapper,在Job类中添加一个构造函数来设置_lastUpdated,并在构造要在仓库的作业检索方法中返回的Job时使用它。

iyr7buue

iyr7buue1#

在我看来,你有很多选择。

选项1

假设你的仓库有两个方法:

public IEnumerable<Job> ReadAll() { ... }
public int CreateJob(Job job) { ... }

您可以给予Job类两个构造函数,一个接受DateTime,另一个不接受。

public class Job
{
    public Job(DateTime startDate)
    {
        this.StartDate = startDate;
    }

    public Job() : this(DateTime.UtcNow)
    {

    }

    public DateTime StartDate { get; private set; }
}

这并不能阻止服务调用“错误的”构造函数,但至少它向调用者传达了在不使用startDate的情况下调用它的选项。

选项二

使用两个不同的Job类。
你的仓库可能看起来像这样:

public IEnumerable<Job> ReadAll() { ... }
public int CreateJob(NewJob newJob) { ... }

NewJob类可能看起来像这样:

public class NewJob
{
    public NewJob()
    {
        this.StartDate = DateTime.UtcNow;
    }

    public DateTime StartDate { get; private set; }
}

这更好地传达了意图,因为存储库的Create方法只接受NewJob的示例,因此模型的用户将被迫创建NewJob而不是Job

备选方案3

忽略reposory的Create方法中的StartDate,并始终在方法中将其设置为DateTime.UtcNow。或者甚至在数据库中创建一个Insert触发器来设置它。

luaexgnf

luaexgnf2#

使用DDD的主要原因之一是利用封装提供的托管可变性。这是总是从构造函数开始。
一般来说,这是ORM专门设计来执行的工作类型,但是它也可以利用任何现有的DTO,这些DTO可以通过使用memento patternMap到域对象上:

public Job() {
    _lastUpdated = DateTime.UtcNow;
    // ...
}

public Job(JobData data) {
    _lastUpdated = data.LastUpdated;
    //...
}

re:AutoMapper-我已经用了一段时间了,但它应该是possible for you to instruct it to access fields using reflection in the configuration

gkn4icbw

gkn4icbw3#

一种常见的方法是使用构造函数来实现

public class Job
{
   private DateTime _startDate;

   public Job()
   {
     _startDate = DateTime.UtcNow;
   }

   public Job(DateTime dt)
   {
     // check DateTime kind, this could be source of a bug
     if(dt.Kind != DateTimeKind.Utc) throw new ...
     _startDate = dt;
   }
}

您必须以某种方式公开此方法/属性。如果存储库可以设置它,您可以从其他位置设置它。如果你试图聪明一点(你可以,例如通过使用接口),你会陷入一个危险的困境。

相关问题