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可能存储了宠物,但没有信息来写正确的外键。 所以它存储了从未出现在任何人的宠物清单中的孤儿。