我们先从技术角度考虑仓储的问题。实体框架(EntityFramework)中,操作数据库是非常简单的:在ObjectContext中使用 LINQ to Entities即可完成操作。开发人员也不需要为事务管理而操心,一切都由EF包办。与原本的ADO.NET以及LINQ to SQL相比,EF更为简单,LINQ to Entities的引入使得软件开发变得更为“领域化”。
下面的代码测试了持久化一个 Customer实体,并从持久化机制中查询这个Customer实体的正确性。从代码中可以看到,我们用了一种很自然的表达方式,表述了“我希望查询一个名字为Sunny的客户”这样一种业务逻辑。
FindCustomerTest
[TestMethod]
public void FindCustomerTest()
{
Customer customer = Customer.CreateCustomer("daxnet", "12345",
new Name { FirstName = "Sunny", LastName = "Chen" },
new Address(), new Address(), DateTime.Now.AddYears(-29));
using (EntitiesContainer ec = new EntitiesContainer())
{
ec.Customers.AddObject(customer);
ec.SaveChanges();
}
using (EntitiesContainer ec = new EntitiesContainer())
{
var query = from cust in ec.Customers
where cust.Name.FirstName.Equals("Sunny")
select cust;
Assert.AreNotEqual(0, query.Count());
}
}
如果你需要实现的系统并不复杂,那么按上面的方式添加、查询实体也不会有太大问题,你可以在 ObjectContext中随心所欲地使用LINQ to Entities来方便地得到你需要的东西,更让人兴奋的是,.NET 4.0允许支持并行计算的PLINQ,如果你的计算机具有多核处理器,你将非常方便地获得效率上的提升。然而,当你的架构需要考虑下面几个方面时,单纯的 LINQ to Entities方式就无法满足需求了:
领域模型与技术架构分离。这是DDD的一贯宗旨,也就是说,领域模型中是不能混入任何技术架构实现的,业务和技术必须严格分离。考察以上实现,领域模型紧密依赖于实体框架,而目前实体框架并非是完全领域驱动的,它更偏向于一种技术架构。比如上面的Customer实体,在实体框架驱动的设计中,它已经被EF“牵着鼻子走”了
规约(Specification)模式的引入。以上实现中,虽然LINQ使得业务逻辑的表述方式更为“领域化”,可以看成是一种 Domain Specific Language(Microsoft Dynamics AX早已引入了类似的语言集成的语法),但这种做法会使得模型对领域概念的描述变得难以更改。比如:可以用“from employee in employees where employee.Age >= 60 && employee.Gender.Equals(Gender.Male) select employee”来表述“找出所有男性退休职工”的概念,但这种逻辑是写死在领域模型中的,倘若某天男性退休的年龄从60岁调至55岁,那么上面的查询就不正确了,此时不得不对领域模型作修改。更可怕的是,LINQ to Entities仍然没有避免“SQL everywhere”的难处,领域模型中将到处充斥这这种LINQ查询,弊端也不多说了。解决方法就是引入规约模式