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

时间:2014-10-27 15:08:30

标签: c# asp.net domain-driven-design

我目前正在使用一个使用Anemic Domain Model的代码库,我正在尝试将更多逻辑转移到域模型中,转向域模型和域驱动设计,但我正在努力解决以下问题。

我有一个名为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,并使用此方法构建要在存储库的作业检索方法中返回的作业时。

3 个答案:

答案 0 :(得分:2)

在我看来,你有各种各样的选择。

选项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

这并不妨碍服务调用&#34;错误&#34;构造函数,但至少它传达了调用它而没有Job给调用者的选项。

选项2

使用两个不同的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而不是StartDate

选项3

忽略repostory的Create方法中的DateTime.UtcNow,并始终在方法中将其设置为Insert。甚至可以在设置它的数据库中创建一个{{1}}触发器。

答案 1 :(得分:1)

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

public class Job
{
   private DateTime _startDate;

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

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

您必须以某种方式公开此方法/属性。如果存储库可以设置它,您可以从其他位置设置它。如果你试图聪明一点(你可以,例如通过使用接口),你就会面临过度工程的风险。

答案 2 :(得分:1)

您正在进行DDD的主要原因之一是利用封装提供的托管可变性。 总是将从构造函数开始。

通常,这是ORM专门设计用于执行的工作类型,但是它也可以利用已使用memento pattern映射到域对象的任何现有DTO:

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

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

重新:AutoMapper - 自从我使用它以来已经过了一段时间了,但它应该是 possible for you to instruct it to access fields using reflection in the configuration