在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 virtual string Name { get; set; }
}
并且不必在Person上创建“特殊”AddPet方法以保存Child宠物。
public void AddPet(Pet p)
{
p.Person = this;
Pets.Add(p);
}
_session.SaveOrUpdate(person);
不保存宠物,因为宠物没有人参考。
如果我更新宠物以包含此参考。
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())
我能想到的唯一其他选项是自定义列表,用于在添加子实体时设置父引用。
答案 0 :(得分:3)
我稍微修改了你的例子(与这里的许多建议一致):
public class Person
{
private IList<Pet> pets;
protected Person()
{}
public Person(string name)
{
Name = name;
pets = new List<Pet>();
}
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual IEnumerable<Pet> 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<Person>
{
public PersonMap()
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.Name);
HasMany(x => x.Pets).Cascade.AllDeleteOrphan().Access.AsLowerCaseField();
}
}
public class PetMap : ClassMap<Pet>
{
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>(person.Id);
Assert.AreEqual("Fido", retrievedPerson.Pets.First().Name);
}
通过。
请注意,这是使用Fluent NHibernate进行映射和Session。
答案 1 :(得分:0)
可以使用这种方法吗?
不适合孩子的孩子,但对父母子女来说非常好。
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);
}
}
答案 2 :(得分:0)
如果您不存储关系,您如何知道一个人在数据库中有哪些宠物?
我会包含
public void AddPet(Pet p)
在Person对象中并有一个
IEnumerable<Pets> Pets { get; }
公共财产。 List属性将受到保护。这样,person.Pets.Add(新的Pet())就不会发生,你就安全了。
答案 3 :(得分:0)
这不是NHibernate问题,而是域模型问题。 NHibernate不负责建立您的域名的引用和反向引用。
我同意gcores,使列表受保护或私有。找到一种以一致的方式将对象链接在一起的方法。如果它不像实现add方法那么简单,请考虑单独的服务类或工厂。 (如果它更复杂,请尝试类似Spring.Net的内容。)
顺便说一句,NHibernate可能存储了宠物,但没有信息来写正确的外键。所以它存储了从未出现在任何人的宠物清单中的孤儿。