我正在使用使用實體框架的域驅動設計構建應用程序。使用域驅動設計與實體框架聚合根
我的目標是讓我的領域模型(即持續使用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;
}
然而,隨着類的當前佈局我可以通過調用organization.Persons.Add(...)
規避AddPerson
邏輯或通過執行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
寫出一個正面,它揭示了我想要的功能。似乎矯枉過正和大量的只讀數據集的維護。
如何在使用實體框架時實現乾淨的DDD模型?
編輯
我使用實體框架V5
您需要將其標記爲虛擬以便自動填充。 – user1496062