Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在存储库中的域模型上设置私有字段_C#_Asp.net_Domain Driven Design - Fatal编程技术网

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

C# 如何在存储库中的域模型上设置私有字段,c#,asp.net,domain-driven-design,C#,Asp.net,Domain Driven Design,我目前正在使用一个使用贫血症领域模型的代码库,我正在尝试将更多的逻辑移到领域模型中,以实现领域模型和领域驱动设计,但我正在努力解决以下问题 我有一个叫做Job的域模型,看起来像这样 public class Job { private DateTime _someOtherDate; private DateTime _lastUpdated; // this may be called from many different services public void

我目前正在使用一个使用贫血症领域模型的代码库,我正在尝试将更多的逻辑移到领域模型中,以实现领域模型和领域驱动设计,但我正在努力解决以下问题

我有一个叫做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,正如您在上面看到的

当我从存储库中的数据库中提取作业时,会出现一个问题,因为我现在没有此字段的公共setter,因为我已将其限制为
setlastpupdated()

有人能告诉我,在检索作业时,如何允许在存储库实现中设置此属性,而不是从服务中设置此属性,该服务仅限于调用
setlastpupdated()

更新1)我已经更新了这个问题,因为使用开始日期是一个坏例子


更新2)根据给出的答案,我能看到这一点的唯一方法是不在存储库中使用AutoMapper,在作业类中添加构造函数以设置_lastUpdated,并在构建要在存储库的作业检索方法中返回的作业时使用它

一种常见的方法是为此使用构造函数

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;
   }
}

您必须以某种方式公开此方法/属性。如果存储库可以设置它,您可以从其他位置设置它。如果您在这方面做得很聪明(例如,您可以使用接口),您将面临过度工程化的风险。

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

一般来说,这是ORM专门设计用来执行的工作类型,但是它也可以利用任何现有DTO,这些DTO本可以通过使用以下命令映射到域对象上:


回复:
AutoMapper
-我使用它已经有一段时间了,但它应该是。

在我看来,您有各种选择

选项1

假设您的存储库有两种方法:

public IEnumerable<Job> ReadAll() { ... }
public int CreateJob(Job job) { ... }
这并不能阻止服务调用“错误”的构造函数,但至少它向调用者传达了在不使用
startDate
的情况下调用它的选项

选项2

使用两种不同的
作业

您的存储库可以如下所示:

public IEnumerable<Job> ReadAll() { ... }
public int CreateJob(NewJob newJob) { ... }
这可以更好地传达意图,因为存储库的
Create
方法只接受
NewJob
的实例,因此模型的用户将被迫创建
NewJob
而不是
Job

选项3


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

您使用什么样的模式来创建域模型?您使用的是ORM还是纪念品?您的构造函数是什么样子的?我正在使用AutoMapper将实体框架模型映射回域模型。这是设置开始日期的地方。域模型上没有构造器,他们的设计贫乏。与论坛网站不同,我们不使用“感谢”或“感谢任何帮助”,也不使用签名。请参阅“.什么域行为使用了_lastUpdated?如果没有,请将其下推到存储级别(如果可能)?虽然您有好的观点,但我不了解两件事。首先,OP的代码没有日期时间字段的getter或setter。只有一种方法“立即将其设置为utc”。因此外部代码无法查看或设置它。因此”当前代码实际上并不能阻止_startDate在将来的任何时候被更改”这似乎是错误的。其次,memento模式有助于将对象的状态恢复到以前的状态。我看不出它与此上下文有何关联。@oleksii我所指的方法签名是
public void SetStartDate()
,此后OP已将其编辑为
public void SetLastUpdated(),我的语句不太适用。我将编辑该部分。至于<代码> MeMeto to /COD>模式,它有助于将对象的状态恢复到其以前的状态。如果数据库中的数据不是对象的前一种状态,您会考虑什么?它可以被认为是前一种状态,如果所有的作业都是事实上的话。e同一对象-只是记录同一对象的不同状态。但是一个表通常会存储许多作业,这些作业很可能不是同一个作业。Memento存储同一对象的突变,但它很难以这种方式应用于存储不同对象的突变。有意义吗?似乎你假设Memento对象没有“没有某种类型的
Id
属性将其与特定实例的状态关联起来,在这种情况下,您是正确的。不过,我认为没有理由做出这种假设-事实上,我的用例要求正好相反的结果才是正确的。感谢您回答Klaus。我认为在示例中使用开始日期是个坏主意。请检查我的更新。您好。”ksii,有趣的检查使用。种类,谢谢!我认为在示例中使用开始日期是一个坏主意。检查我的更新。@Jonathan C#DateTime是一个很难处理的问题。你会看到这个异常会引发很多。我们在这个方面有一些错误。当ORM(Automapper)创建一个新的日期时间,默认情况下,如果我没记错的话,种类是未指定的。这个对象会很乐意接受utc日期,但会“忘记”设置utc种类。
public class Job
{
    public Job(DateTime startDate)
    {
        this.StartDate = startDate;
    }

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

    }

    public DateTime StartDate { get; private set; }
}
public IEnumerable<Job> ReadAll() { ... }
public int CreateJob(NewJob newJob) { ... }
public class NewJob
{
    public NewJob()
    {
        this.StartDate = DateTime.UtcNow;
    }

    public DateTime StartDate { get; private set; }
}