C# NHibernate中的子表
在NHibernate中是否有任何方法可以使用以下实体C# NHibernate中的子表,c#,nhibernate,C#,Nhibernate,在NHibernate中是否有任何方法可以使用以下实体 public class Person { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual IList<Pet> Pets { get; set; } } public class Pet { public virtual int Id { get; set;
public class Person
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Pet> Pets { get; set; }
}
public class Pet
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
不保存宠物,因为宠物没有个人参考
public class Pet
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Person Person { get; set; }
}
如果我更新宠物以包含此引用
public class Pet
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Person Person { get; set; }
}
在新宠物身上,我仍然需要安排一个人,这对我来说似乎是杀伤力过大,而且风险也很大,因为人们仍然可以打电话给我
person.Pets.Add(new Pet())
我唯一能想到的另一个选项是自定义列表,它在添加子实体时设置父引用。
也许可以使用这种方法
这对孩子的孩子不起作用,但对父母的孩子却很好
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<PropertyInfo> propsToSet = new List<PropertyInfo>();
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<PropertyInfo> properties, object target, object value)
{
foreach (PropertyInfo property in properties)
{
property.SetValue(target, value, null);
}
}
受保护的静态void SetChildReferences(E父级)
{
foreach(typeof(E).GetProperties中的var prop(BindingFlags.Public | BindingFlags.Instance))
{
如果(!prop.CanRead)继续;
类型listType=null;
foreach(prop.PropertyType.GetInterfaces()中的类型)
{
如果(type.IsGenericType&&
type.GetGenericTypeDefinition()==typeof(ICollection))
{
listType=type.GetGenericArguments()[0];
打破
}
}
List propsToSet=新列表();
foreach(属性信息中的childProp)
(listType??prop.PropertyType).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if(childProp.PropertyType==typeof(E))
propsToSet.Add(childProp);
}
如果(propsToSet.Count==0)继续;
if(listType==null)
{
对象子对象=prop.GetValue(父对象,null);
如果(child==null)继续;
更新属性(propsToSet、子级、父级);
}
其他的
{
ICollection collection=(ICollection)prop.GetValue(父级,null);
foreach(集合中的对象子对象)
{
如果(child==null)继续;
更新属性(propsToSet、子级、父级);
}
}
}
}
受保护的静态void UpdateProperties(列表属性、对象目标、对象值)
{
foreach(属性中的PropertyInfo属性)
{
SetValue(target,value,null);
}
}
如果不存储关系,您如何知道一个人在数据库中有哪些宠物
我会包括
public void AddPet(Pet p)
在Person对象中,有一个
IEnumerable<Pets> Pets { get; }
IEnumerable宠物{get;}
公共财产。列表属性将受到保护。这样,person.Pets.Add(new Pet())就不会发生,您就安全了。这不是NHibernate问题,而是域模型问题。NHibernate不负责建立您的域的引用和反向引用 我同意gcores的观点,将列表设置为受保护的或私有的。找到一种方法以一致的方式将对象链接在一起。如果它不像实现Add方法那样简单,请考虑一个单独的服务类或工厂。(如果它更复杂,请尝试类似Spring.Net的东西。)
顺便说一句,NHibernate可能存储了宠物,但没有写入正确外键的信息。因此,它存储了从未出现在任何人的宠物列表中的孤儿宠物。我只是稍微修改了您的示例(与这里的许多建议一致):
公共类人物
{
私人宠物;
受保护人()
{}
公众人物(字符串名称)
{
名称=名称;
pets=新列表();
}
公共虚拟Guid Id{get;set;}
公共虚拟字符串名称{get;set;}
公共虚拟宠物
{
获取{返回宠物;}
}
公共虚拟空间添加宠物(宠物宠物)
{
宠物。添加(宠物);
}
}
公营宠物
{
受保护宠物()
{}
公共宠物(字符串名称)
{
名称=名称;
}
公共虚拟Guid Id{get;set;}
公共虚拟字符串名称{get;set;}
}
公共类PersonMap:ClassMap
{
公众人物地图()
{
Id(x=>x.Id).GeneratedBy.GuidComb();
Map(x=>x.Name);
HasMany(x=>x.Pets).Cascade.AllDeleteOrphan().Access.AsLowerCaseField();
}
}
公共类PetMap:ClassMap
{
公共地图()
{
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>(person.Id);
Assert.AreEqual("Fido", retrievedPerson.Pets.First().Name);
}
[测试]
public void可以保存和检索petattachedtoperson()
{
人员=新人员(“乔”);
person.AddPet(新宠物(“Fido”));
会话。保存(个人);
Person retrievedPerson=Session.Get(Person.Id);
Assert.AreEqual(“Fido”,retrievedPerson.Pets.First().Name);
}
通行证
请注意,这是使用Fluent NHibernate进行映射和会话。是的,我知道这是一种方式,我的问题是宠物是否在一个人的宠物集合中推断出这种关系?不,我没有,因为它没有关系。我的意思是,如果你重新加载一个人,你不能重新加载这个人的宠物,因为没有办法知道哪些宠物会属于那个人。这就是为什么你需要一个人的宠物财产。这不是NHibernate的问题,这是DB的问题。仔细考虑后,我同意你和其他人的看法,这是一个领域问题,而不是NHibernate的问题。
[Test]
public void CanSaveAndRetrievePetAttachedToPerson()
{
Person person = new Person("Joe");
person.AddPet(new Pet("Fido"));
Session.Save(person);
Person retrievedPerson = Session.Get<Person>(person.Id);
Assert.AreEqual("Fido", retrievedPerson.Pets.First().Name);
}