gpt4 book ai didi

c# - 使用域驱动设计将根与 Entity Framework 聚合

转载 作者:太空狗 更新时间:2023-10-29 19:55:57 25 4
gpt4 key购买 nike

我正在构建一个使用领域驱动设计的应用程序,该应用程序正在使用 Entity Framework 。

我的目标是让我的域模型(通过 EF 持久化)在其中包含一些逻辑。

开箱即用, Entity Framework 对于如何将实体添加到图形中然后持久化没有任何限制。

例如,我的域是 POCO(没有逻辑):

public class Organization
{
private ICollection<Person> _people = new List<Person>();

public int ID { get; set; }

public string CompanyName { get; set; }

public virtual ICollection<Person> People { get { return _people; } protected set { _people = value; } }
}

public class Person
{
public int ID { get; set; }

public string FirstName { get; set; }
public string LastName { get; set; }

public virtual Organization Organization { get; protected set; }
}

public class OrganizationConfiguration : EntityTypeConfiguration<Organization>
{
public OrganizationConfiguration()
{
HasMany(o => o.People).WithRequired(p => p.Organization); //.Map(m => m.MapKey("OrganizationID"));
}
}

public class PersonConfiguration : EntityTypeConfiguration<Person>
{
public PersonConfiguration()
{
HasRequired(p => p.Organization).WithMany(o => o.People); //.Map(m => m.MapKey("OrganizationID"));
}
}

public class MyDbContext : DbContext
{
public MyDbContext()
: base(@"Data Source=(localdb)\v11.0;Initial Catalog=stackoverflow;Integrated Security=true")
{
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new PersonConfiguration());
modelBuilder.Configurations.Add(new OrganizationConfiguration());
}

public IDbSet<Organization> Organizations { get; set; }
public IDbSet<Person> People { get; set; }
}

我的示例域是一个组织可以有很多人。一个人只能属于一个组织。

创建组织并向其添加人员非常简单:

using (var context = new MyDbContext())
{
var organization = new Organization
{
CompanyName = "Matthew's Widget Factory"
};

organization.People.Add(new Person {FirstName = "Steve", LastName = "McQueen"});
organization.People.Add(new Person {FirstName = "Bob", LastName = "Marley"});
organization.People.Add(new Person {FirstName = "Bob", LastName = "Dylan" });
organization.People.Add(new Person {FirstName = "Jennifer", LastName = "Lawrence" });

context.Organizations.Add(organization);

context.SaveChanges();
}

我的测试查询是。

var organizationsWithSteve = context.Organizations.Where(o => o.People.Any(p => p.FirstName == "Steve"));

上面的类布局不符合域的工作方式。例如,所有人都属于一个组织,组织是聚合根。能够做到 context.People.Add(...) 没有意义因为这不是域的工作方式。

如果我们想向 Organization 添加一些逻辑限制该组织中可以有多少人的模型,我们可以实现一种方法。

public Person AddPerson(string firstName, string lastName)
{
if (People.Count() >= 5)
{
throw new InvalidOperationException("Your organization already at max capacity");
}

var person = new Person(firstName, lastName);
this.People.Add(person);
return person;
}

但是,使用当前的类布局,我可以绕过 AddPerson通过调用逻辑 organization.Persons.Add(...)或者通过执行 context.Persons.Add(...) 完全忽略聚合根,我都不想做。

我提出的解决方案(不起作用,这也是我将其发布在这里的原因)是:

public class Organization
{
private List<Person> _people = new List<Person>();

// ...

protected virtual List<Person> WritablePeople
{
get { return _people; }
set { _people = value; }
}

public virtual IReadOnlyCollection<Person> People { get { return People.AsReadOnly(); } }

public void AddPerson(string firstName, string lastName)
{
// do domain logic / validation

WriteablePeople.Add(...);
}
}

这不适用于映射代码 HasMany(o => o.People).WithRequired(p => p.Organization);不编译为 HasMany期望一个 ICollection<TEntity>而不是 IReadOnlyCollection .我可以公开一个 ICollection本身,但我想避免拥有 Add/Remove方法。

我可以“忽略”People属性,但我仍然希望能够针对它编写 Linq 查询。

我的第二个问题是我不希望我的上下文公开直接添加/删除人员的可能性。

在我想要的上下文中:

public IQueryable<Person> People { get; set; }

但是,EF 不会填充 People我上下文的属性,即使IDbSet工具 IQueryable .我能想到的唯一解决方案是在 MyDbContext 上写一个门面它公开了我想要的功能。对于只读数据集来说,这似乎有点矫枉过正,需要大量维护。

如何在使用 Entity Framework 时实现干净的 DDD 模型?

编辑
我正在使用 Entity Framework v5

最佳答案

正如您所注意到的,持久性基础结构 (EF) 对类结构提出了一些要求,因此使其不像您期望的那样“干净”。只怕苦苦挣扎,终将是无休止的挣扎和脑洞。

我建议另一种方法,一个完全干净的域模型和一个在较低层中的单独的持久性模型。您可能需要这两者之间的转换机制,AutoMapper 就可以了。

这将使您完全摆脱担忧。没有办法仅仅因为 EF 使事情变得必要并且上下文从域层不可用,因为它只是来自“另一个世界”,它不属于域,所以没有办法“分一杯羹”。

我见过有人制作部分模型(又名“限界上下文”)或只是创建一个普通的 EF poco 结构并假装这是 DDD,但它可能不是,你的顾虑正好击中了要害。

关于c# - 使用域驱动设计将根与 Entity Framework 聚合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17843310/

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