我掏了很多关于DDD做法事(无处不在的语言,聚合,资源库等),我认为,相反,我读了很多,实体要有行为,而随后是不可知的。 所有的例子我看到的往往将虚拟自动属性和一个空的构造 (保护或最差,公众)的实体,就是这样。 我认为这种对象更像DTO的那么实体。
我在创建具有其特定的API 框架的过程中,我不希望被束缚的ORM。 所以我先建的网域(不含持久性的思维),现在我想用NHibernate的持久化工具,所以我增加了一个新的项目,以我目前的解决方案,以帮助确保我的模型不会改变支持NHibernate的。 这个项目应该是住在我的域内抽象库的实现。 而现在的困难出现。
由于这是我第一次与NHibernate(我也想流利NHibernate的,但它似乎更限制),我想知道:
- 是否有可能使用NHibernate的,而不会改变一个DDD模型是一个框架的一部分
- 这是必要的NHibernate的按预期的方式,有效地(虚拟特性,空构造函数等)工作的事情(限制),我认为这个名单将是有益的很多人谁也开始学习NHibernate的。
请记住,我建立一个框架,以便在开/闭原则对我来说非常重要。
PS:很抱歉,如果我的英语不是很好,我从蒙特利尔是和我讲法语。
编辑1:这里有一个问题,我现在有NHibernate的- 如何与NHibernate(和功能NHibernate)地图类型
简短的回答你的问题是,它是不可能的,但如果不需要延迟加载所需要的变化是微不足道的。
不管是什么,你将不得不添加默认构造函数不已经有他们的类。 如果你愿意放弃延迟加载,这些默认构造函数可以是私有的, 你不必做任何其他更改您的域模型中使用NHibernate的。
这是非常接近持久性的无知。
说了这么多,如果你想延迟加载,你需要做出一些改变(在其他的答案中概述了这个问题),这样NHibernate的可以创建聚合实体的代理。 我个人仍然试图决定是否延迟加载是DDD一个有利的技术,或者如果它是需要我的波苏斯太多的侵入改变一个不成熟的优化。 我倾向于前者,但我真的希望NHibernate的可以配置为使用特定的构造函数。
你也可以看看戴维酒庄的博客(我特别喜欢实现价值目标与NHibernate ),如果你感兴趣的领域驱动设计,避免贫血域模型这实在是照明。
- 对于NHibernate的:
- 所有映射类需要一个默认的(无参数)构造函数。 默认的构造并不一定是公共的(也可以是私人,它不是API的一部分),但是它必须存在。 这是因为NHibernate的必须能够在不传递任何参数来创建映射类的一个实例。 (有解决方法,但不这样做。)
- 针对延迟加载将所需的所有映射属性必须注明
virtual
。 这包括所有的参考属性和所有集合属性。 这是因为NHibernate的必须能够生成一个代理类派生的映射类并覆盖对应的属性。 - 所有映射集合属性应该使用一个接口作为属性类型。 例如,使用
IList<T>
而不是List<T>
这是因为集合类型在.NET Framework往往是密封的,和NHibernate必须能够与自己的集合类型的实例来代替集合类型的默认实例,和NHibernate拥有集合类型的自己的内部实现。 - 对于NHibernate的,喜欢
Iesi.Collections.Generic.ISet<T>
到System.Collections.Generic.IList<T>
除非你确信你想要的东西实际上是一个列表 ,而不是一组 。 这就要求正在列表的理论定义,熟悉并设置在你的领域模型需要。 当你知道的元素必须是在某些特定的顺序使用列表。
另外请注意,这通常不容易掉的对象关系映射框架,在很多情况下是不可能的,当你有任何超出一个简单的域模型。
在我的经验,NHibernate的要求域的唯一的事情是虚拟的属性和方法,默认的无参数的构造函数,这是杰夫提到的,可以标记私有或保护如果需要的话。 而已。 NHibernate的是选择我的OR / M,我觉得整个NHibernate的堆栈(NHibernate的,NHibernate的验证,功能NHibernate,LINQ NHibernate的)成为持续POCO领域最引人注目的框架。
有几件事情,你可以与NHibernate做:
- 装饰你的域模型与NHV属性。 这些constaints让你做三两件事:验证对象,确保无效的实体不通过NHibernate的坚持,并帮助使用使用NHibernate的SchemaExport工具或SchemaUpdate工具工具时自动生成的架构。
- 地图你的域模型使用功能NHibernate的持久性存储。 主要优点,对我来说,在使用FNH是能够根据您设置约定自动映射您的实体。 Additonally,您可以覆盖这些automappings在必要时手动编写类映射到采取映射的完全控制,如果你需要使用XML HBM文件。
- 一旦你购买到使用NH,您可以轻松地使用的SchemaExport或SchemaUpdate工具的工具来创建和执行DDL对你的数据库,让您域的变化自动迁移到你的数据库initilizing的NH会话工厂时。 这可以让你忘记数据库,对所有意图和目的,而是专注于你的域。 请注意,这可能不是有用的或在许多情况下理想的,但对于域为中心的应用程序的快速,地方发展,我觉得很方便。
- 此外,我喜欢使用通用库来处理CRUD场景。 例如,我通常有定义了让所有的entites作为一个IQueryable,由ID一个单一的实体,保存一个实体,并删除实体法的IRepository。 为别的,NH提供了丰富的查询机制的 - 你可以使用LINQ到NHibernate的,HQL,条件查询和直接的SQL如果需要的话。
钍只妥协你正在使用NHV在您的域的属性进行。 这不是对我来说是大忌,因为NHV是一个独立的框架,如果你选择使用NHibernate的它增加了额外的功能。
我已经建立了使用NH一些应用程序,每个有分离到自己组装的所有持续性的担忧持续性无知的领域。 这意味着对域中的一个组件,另一个用于流利的映射,会话管理和验证的集成。 这是非常漂亮,干净,做的工作做好。
顺便说一句:你的英语是相当不错的,我希望我的法语达到标准;-)。
只是把我的两个位,我有同样的事情挣扎一次,但我通过克服了这个:
- 添加受保护的默认构造函数的每一个实体。
- 制作标识虚
让我们举个例子给予好评和downvote的投票实体在我的实验网站: http://chucknorrisfacts.co.uk/ (NHibernate的+ MySQL的使用Mono)
public class Vote : Entity
{
private User _user;
private Fact _fact;
// true: upvote, false: downvote
private bool _isupvoted;
// for nHibernate
protected Vote() { }
public Vote(User user, Fact fact, bool is_upvoted)
{
Validator.NotNull(user, "user is required.");
Validator.NotNull(fact, "fact is required.");
_fact= fact;
_user = user;
_isupvoted = is_upvoted;
}
public User User
{
get { return _user; }
}
public Fact Fact
{
get { return _fact; }
}
public bool Isupvoted
{
get { return _isupvoted; }
}
}
这个类的实体 ,我们坚持一切必要NHibernate的最低继承。
public abstract class Entity
{
protected int _id;
public virtual int Id { get {return _id;} }
}
和流利的映射,其中你显示的私有财产。
public class VoteMap : ClassMap<Vote>
{
public VoteMap()
{
DynamicUpdate();
Table("vote");
Id(x => x.Id).Column("id");
Map(Reveal.Member<Vote>("_isupvoted")).Column("vote_up_down");
References(x => x.Fact).Column("fact_id").Not.Nullable();
References(x => x.User).Column("user_id").Not.Nullable();
}
}
你也许可以放在实体类保护默认的构造和配置NHibernate的,而不是使用它,但我并没有考虑它。
文章来源: Is it possible to use NHibernate without altering a DDD model that is part of a framework