我正在尝试学习NH(版本3.2)并且在理解某些映射选择时遇到了问题。斯科特Findlater已经发布了他的性感Loquacious NH here完全工作的骨架,我关于贴图的问题将基于他的样本。 这是域模型(图片不是他的样本的一部分,但为了清楚起见包括在这里):
他的类别类看起来像这样:
public class Category : Entity
{
public Category()
{
Products = new List<Product>();
SubCategories = new List<Category>();
}
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual Category Parent { get; set; }
public virtual IEnumerable<Category> SubCategories { get; set; }
public virtual IList<Product> Products { get; set; }
}
和他的映射类如下:
class CategoryMap : ClassMapping<Category>
{
public CategoryMap()
{
// **************************************************
// Mapping of Id here will take precedence over the
// global conventions configured in the ModelMapper.
// **************************************************
//Id(x => x.Id, map =>
//{
// map.Column("Id");
// map.Generator(Generators.GuidComb);
//});
Property(x => x.Name, m => m.Length(450));
Property(x => x.Description, m => m.Length(2000));
Set(x => x.SubCategories, set =>
{
set.Key(k => k.Column("ParentCategoryId"));
set.Inverse(true);
} ,
ce => ce.OneToMany());
ManyToOne(x => x.Parent, manyToOne =>
{
manyToOne.Column("ParentCategoryId");
manyToOne.Lazy(LazyRelation.NoLazy);
manyToOne.NotNullable(false);
});
Set(x => x.Products, set =>
{
set.Key(key =>
{
key.Column("ProductId");
key.ForeignKey("FK_Product_Category_ProductId");
});
set.Table("Product_Category");
},
ce => ce.ManyToMany(m => m.Column("CategoryId")));
}
}
现在,对于问题:
1)为什么他选择将Parent属性映射/建模为ManyToOne关系?这是否表明类别可以属于多个父类别,即任何给定的类别(我认为除根之外)可以分散在许多其他父类别中?如果是这样,那么从模型本身就不是很清楚了,因为对我来说,Parent(我在类定义中看到它)看起来像是Category类型的属性,我会像那样映射它。你什么时候选择在这个解决方案中的方法vs.s.将其映射为简单属性?
2)当我映射文件时,我应该从哪个(或哪个)视角看?在我看来,这是来自你想要映射的类的内部。所以,在这种情况下,当我尝试映射Category类时,我只关心映射出去的“箭头”,对吗?
3)创建映射文件的人必须通过查看类才能掌握清晰的知识。查看Products属性的映射方式(ManyToMany关系)。从类本身来看,很明显Category可能属于许多产品,但Category不知道它可能包含在许多产品中。这一事实对于Product类来说是显而易见的。现在我已经说过,在我看来,当我创建映射文件时,我应该从类的角度来看,然后是模型。
4)一般来说:你什么时候使用.Inverse(),. Cascade()和.Lazy()?
5)使用ModelMapper和ConventionModelMapper进行映射有什么区别?我没有研究使用后一种方法的同一项目中包含的文件,但我想知道除了偏好之外是否有使用另一种方法的优势。
答案 0 :(得分:3)
Scott决定在类别及其父级(另一个)类别之间建立Ordinary Association(many-to-one)关联。通过多对一关联,您可以访问在属性映射中找不到的级联和提取策略等功能。例如,假设您要删除父项及其所有子项。 Cascades可以帮助你。
如果您有关联,则必须考虑关联的两个方面。例如,假设您在'A'和'B'之间存在双向一对多关联,则需要注意哪一方管理关系。在为'A'编写映射时,您会考虑'A'与之相关的方式,而在映射'B'时则反之亦然强>
你的观点有点不清楚。但是,您似乎要描述的是基本的OOP对象关系。一个类可能具有属性'A',这是与对象'B'的关系,而'B'又可能与有关'C'即可。仅仅通过查看'A'就无法确定它与'C'的传递性相关。这没有什么不妥。
4.1 Inverse:定义双向关系的哪一侧管理关系。
4.2级联:允许某些操作级联到子关联。 (例如删除)
4.3 Lazy:定义加载集合的策略。 (热切/懒洋洋)
ConventionalModelMapper构建于ModelMapper之上,提供便捷方法和默认映射约定,使常规映射体验更容易。
答案 1 :(得分:1)
对于 1。这并不意味着每个类别都有多个父类别,这意味着许多类别可能表示在同一个父类别中,每个类别可以有一个列表子类别。如果它被表达为一对一,那就意味着每个类别只有一个类别,我认为你并不是故意这样做。
对于 4。 Inverse()
用于指定关联的所有者,因此您可以在一对多关系中使用它,而子实体不是关系的所有者或子实体将不对该关系负责,并且它不知道该关系,因此如果将其设置为true,则NHibernate将不会尝试插入或更新由该连接定义的属性。 / p>
Cascade()
指定将从父实体级联到关联实体的操作。
lazy
用于延迟加载其他实体引用的实体。
对于2.和3.我无法理解你的意思和你的意思,但我认为当你映射一个实体时,你应该从你正在映射的类的角度来看,当您进行映射时,对于关系的另一方来说,同样的事情,从它的角度来看,同时你应该考虑关系的两个方面。