NHibernate中的子表

在NHibernate中有什么方法我可以使用以下实体

public class Person { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual IList Pets { get; set; } } public class Pet { public virtual int Id { get; set; } public virtual string Name { get; set; } } 

并且不必在Person上创建“特殊”AddPet方法以便保存Child宠物。

 public void AddPet(Pet p) { p.Person = this; Pets.Add(p); } _session.SaveOrUpdate(person); 

不保存宠物,因为宠物没有人参考。

如果我更新Pets以包含此参考。

 public class Pet { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual Person Person { get; set; } } 

在新的宠物上我仍然需要设置Person这对我来说似乎有点过头了,而且人们仍然可以打电话

 person.Pets.Add(new Pet()) 

我能想到的唯一另一个选项是自定义列表,它在添加子实体时设置父引用。

我稍微修改了你的例子(符合这里的许多建议):

 public class Person { private IList pets; protected Person() {} public Person(string name) { Name = name; pets = new List(); } public virtual Guid Id { get; set; } public virtual string Name { get; set; } public virtual IEnumerable Pets { get { return pets; } } public virtual void AddPet(Pet pet) { pets.Add(pet); } } public class Pet { protected Pet() {} public Pet(string name) { Name = name; } public virtual Guid Id { get; set; } public virtual string Name { get; set; } } public class PersonMap : ClassMap { public PersonMap() { Id(x => x.Id).GeneratedBy.GuidComb(); Map(x => x.Name); HasMany(x => x.Pets).Cascade.AllDeleteOrphan().Access.AsLowerCaseField(); } } public class PetMap : ClassMap { public PetMap() { Id(x => x.Id).GeneratedBy.GuidComb(); Map(x => x.Name); } } 

以下测试:

  [Test] public void CanSaveAndRetrievePetAttachedToPerson() { Person person = new Person("Joe"); person.AddPet(new Pet("Fido")); Session.Save(person); Person retrievedPerson = Session.Get(person.Id); Assert.AreEqual("Fido", retrievedPerson.Pets.First().Name); } 

经过。

请注意,这是使用Fluent NHibernate进行映射和Session。

C#Reflection&Generics

可以使用这种方法吗?

不适合儿童的孩子,但对父母子女来说非常好。

 protected static void SetChildReferences(E parent) { foreach (var prop in typeof(E).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (!prop.CanRead) continue; Type listType = null; foreach (Type type in prop.PropertyType.GetInterfaces()) { if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ICollection<>)) { listType = type.GetGenericArguments()[0]; break; } } List propsToSet = new List(); foreach (PropertyInfo childProp in (listType ?? prop.PropertyType).GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (childProp.PropertyType == typeof(E)) propsToSet.Add(childProp); } if (propsToSet.Count == 0) continue; if (listType == null) { object child = prop.GetValue(parent, null); if (child == null) continue; UpdateProperties(propsToSet, child, parent); } else { ICollection collection = (ICollection)prop.GetValue(parent, null); foreach (object child in collection) { if (child == null) continue; UpdateProperties(propsToSet, child, parent); } } } } protected static void UpdateProperties(List properties, object target, object value) { foreach (PropertyInfo property in properties) { property.SetValue(target, value, null); } } 

如果你不存储关系,你如何知道一个人在数据库中有哪些宠物?

我会包括

 public void AddPet(Pet p) 

在Person对象中有一个

 IEnumerable Pets { get; } 

公共财产。 List属性将受到保护。 这样,person.Pets.Add(新的Pet())不会发生,你是安全的。

这不是NHibernate问题,而是域模型问题。 NHibernate不负责建立您的引用和您域的引用。

我同意gcores,使列表受保护或私有。 找到一种以一致的方式将对象链接在一起的方法。 如果它不像实现add方法那么简单,请考虑单独的服务类或工厂。 (如果它更复杂,请尝试像Spring.Net这样的东西。)

顺便说一句,NHibernate可能存储了宠物,但没有信息来写正确的外键。 所以它存储了从未出现在任何人的宠物清单中的孤儿。