C# DDD和实体框架类
我已经阅读了许多关于DDD的文章,并且理解到,我应该在基础设施级别使用我的域模型类,因此,我应该使用与实体框架基础设施相同的类,并使用它们生成表(代码优先方法)等。但是我的域模型可以完全不同于关系数据库模型C# DDD和实体框架类,c#,entity-framework,model,domain-driven-design,C#,Entity Framework,Model,Domain Driven Design,我已经阅读了许多关于DDD的文章,并且理解到,我应该在基础设施级别使用我的域模型类,因此,我应该使用与实体框架基础设施相同的类,并使用它们生成表(代码优先方法)等。但是我的域模型可以完全不同于关系数据库模型 为什么我不能再创建一个模型,即infrastructure model来创建关系数据库模型,而不将域模型与EF类混合使用?考虑以下简单示例: 域模型 public class Customer { public Customer(IRegistrar registrar) {
为什么我不能再创建一个模型,即infrastructure model来创建关系数据库模型,而不将域模型与EF类混合使用?考虑以下简单示例: 域模型
public class Customer
{
public Customer(IRegistrar registrar)
{
this.registrar = registrar;
}
public int Age
{
get
{
// Just for this example. This will not work for all locals etc but beyond the point here.
var today = DateTime.Today;
return today.Year - this.DateOfBirth.Year;
}
}
public DateTime DateOfBirth { get; set; }
public int Register()
{
if (this.Age < 18)
{
throw new InvalidOperationException("You must be at least 18 years old");
}
int id = this.registrar.Register(this);
return id;
}
}
public interface IRegistrar
{
public int Register(Customer customer);
}
EF型号
public class Customer
{
public Customer(IRegistrar registrar)
{
this.registrar = registrar;
}
public int Age
{
get
{
// Just for this example. This will not work for all locals etc but beyond the point here.
var today = DateTime.Today;
return today.Year - this.DateOfBirth.Year;
}
}
public DateTime DateOfBirth { get; set; }
public int Register()
{
if (this.Age < 18)
{
throw new InvalidOperationException("You must be at least 18 years old");
}
int id = this.registrar.Register(this);
return id;
}
}
public interface IRegistrar
{
public int Register(Customer customer);
}
您的EF模型可能如下所示:
public int Register(Customer customer)
{
var today = DateTime.Today;
var age = today.Year - this.DateOfBirth.Year;
if (age < 18)
{
// Return a SOAP fault or some other error
}
int id = this.registrar.Register(customer);
// The rest of code
}
public class Customer
{
public int Id { get; set; }
public DateTime DateOfBirth { get; set; }
// It may have a foreign key etc.
}
public class Customer
{
// Or instead of Domain.Customer, it may be a CustomerDto which is used
// to transfer data from one layer or tier to another.
// But you get the point.
public Customer(Domain.Customer customer)
{
this.DateOfBirth = customer.DateOfBirth;
this.Age = customer.Age;
if (this.DateOfBirth.DayOfYear == DateTime.Today.DayOfYear)
{
this.Greeting = "Happy Birthday!!!";
}
}
public int Age { get; set; }
[Required(ErrorMessage = "Date of birth is required.")]
[Display(Name = "Data of birth")]
public DateTime DateOfBirth { get; set; }
public string Greeting { get; set; }
}
应用层模型
public class Customer
{
public Customer(IRegistrar registrar)
{
this.registrar = registrar;
}
public int Age
{
get
{
// Just for this example. This will not work for all locals etc but beyond the point here.
var today = DateTime.Today;
return today.Year - this.DateOfBirth.Year;
}
}
public DateTime DateOfBirth { get; set; }
public int Register()
{
if (this.Age < 18)
{
throw new InvalidOperationException("You must be at least 18 years old");
}
int id = this.registrar.Register(this);
return id;
}
}
public interface IRegistrar
{
public int Register(Customer customer);
}
您的MVC视图模型可能如下所示:
public int Register(Customer customer)
{
var today = DateTime.Today;
var age = today.Year - this.DateOfBirth.Year;
if (age < 18)
{
// Return a SOAP fault or some other error
}
int id = this.registrar.Register(customer);
// The rest of code
}
public class Customer
{
public int Id { get; set; }
public DateTime DateOfBirth { get; set; }
// It may have a foreign key etc.
}
public class Customer
{
// Or instead of Domain.Customer, it may be a CustomerDto which is used
// to transfer data from one layer or tier to another.
// But you get the point.
public Customer(Domain.Customer customer)
{
this.DateOfBirth = customer.DateOfBirth;
this.Age = customer.Age;
if (this.DateOfBirth.DayOfYear == DateTime.Today.DayOfYear)
{
this.Greeting = "Happy Birthday!!!";
}
}
public int Age { get; set; }
[Required(ErrorMessage = "Date of birth is required.")]
[Display(Name = "Data of birth")]
public DateTime DateOfBirth { get; set; }
public string Greeting { get; set; }
}
这里有一个问题:您见过多少带有Display
属性的EF模型?我将让您决定EF模型是否应该关注它在UI中的显示方式。只是假设我的EF模型将显示在UI中是错误的。也许我们班上唯一的消费者是另一个web服务。我不认为EF模型中应该有显示
,但有些可能不同意我的观点;你打电话
stackoverflow上有很多问题,人们问有时需要PropertyX,有时不需要,我怎么做?如果您没有在EF模型上添加Required
属性并在视图中使用EF模型,那么您就不会有这个问题。视图将有一个模型,其中PropertyX是必填字段。该模型将使用Required
属性装饰PropertyX,而不需要PropertyX的视图的另一个模型将不会使用Required
属性装饰属性
视图模型 然后,您可以为WPF应用程序的客户提供一个viewmodel,也可以为前端提供一个javascript viewmodel(KnockoutJS viewmodel)
结论和问题的答案 总之,您可以拥有不同于实体模型的域模型。您的域模型应该不知道数据库。如果由于规范化而决定从一个表中删除一列,并将其放入自己的表中,则实体模型将受到影响。您的域模型不应受到影响 我在网上读到过一些争论,比如“这个设计花的时间太长了,我只是想快速推出一些东西,并把它交给客户,然后得到报酬”。如果你不是在设计一个需要维护和添加功能的产品,但是你只是在为你的客户设计一个快速的小网站,那么不要使用这种方法。没有一种设计适用于所有情况。需要注意的是,您的设计应该明智地选择,并考虑到未来 此外,从实体模型到域到MVC模型的转换也不需要手动完成。有一些库可以很容易地为您做到这一点,例如
但我必须承认,网上有大量的例子,在许多应用程序中也有使用,实体模型在整个应用程序中使用,规则在任何地方都用大量的if语句实现 这与DDD的关系 当我读到你的问题时,我发现一些吸引眼球的东西。这是: 我已经阅读了许多关于DDD的文章,并且了解到,我应该在基础设施级别使用我的域模型类,因此,我应该使用与实体框架基础设施相同的类,并使用它们生成表(代码优先方法) 老实说,DDD知识的最好来源仍然是蓝皮书。我知道,我知道,它很厚,很难读。可以看看弗农蒸馏的DDD。结论应该是,DDD并不是真正处理持久性,而是更深入地了解领域,更好地理解领域专家。当然,它没有提到ORM 域模型持久性 域模型通常由具有状态和行为的对象(如果我们谈论面向对象的模型)组成。模型将有一个或多个实体,可能是一些值对象。在许多情况下,每个有界上下文只有一个实体。实体以集合的形式分组,这些集合一起变化,形成事务边界。这意味着聚合中的每个更改都是一个事务,无论此更改涉及多少个实体。每个聚合都有一个且只有一个实体,即聚合根,它公开了公共方法,供其他人使用整个聚合 因此,您的存储库应注意:
- 在一个事务中为新对象和更新对象持久化整个聚合(无论有多少个实体)
- 通过其标识(聚合根
property)从持久性存储中获取整个聚合Id
DbContext
扩展方法将它们实现为一个单独的静态类
相互不匹配的型号
你提到你的坚持