在我的应用程序中,我需要使用分离的对象并且已经实现了reporitory模式。问题出现在以下代码示例中:
var shops = ShopRepository.GetAll(); //Session.Clear() called inside, CacheMode = CacheMode.Ignore
var employees = EmployeeRepository.GetAll(); //same here
// Case 1: Session.Save() works, Session.Merge() irgnores the changes
employees.First().WorksAt.Name = "le new Shop in Town";
EmployeeRepository.Save(employees.First());
// Case 2: Session.Merge() works, Session.Save() throws NonUniqueObjectException
employees.First().WorksAt = employees.Last().WorksAt;
EmployeeRepository.Save(employees.First());
首先需要加载商店,因此用户可以通过ComboBox(或类似的东西)设置“WorksAt” - 员工的财产。
我的期望是,在调用Session.Clear()之后,nhibernate“忘记”所有实例(以及底层图形)。事实并非如此。我仍然在Update() - 操作上得到NonUniqueObjectException。所以,我无法使用SaveOrUpdate,尽管它可以很好地处理对象图形的所有类型的更改。
Session.Merge()只能完成一半的工作:
没有抛出任何异常,保存了新的引用,但是对商店属性所做的更改没有得到保存(因为merge只是从缓存中加载“旧”员工/商店对象并将employee-properties复制到旧版本实例)
我已经尝试过的事情:
该模型包含~50个实体,因此(重新)加载会话中保存/更新的每个引用的bo实例不是一个选项。目前我正在使用nHibernate 3.3.0.4和FluentNHibernate 1.3。
是否有紧凑/优雅的解决方案可以覆盖这两种情况? 也许禁用NHibernate的内部id跟踪会解决问题吗?
映射可能如下所示:
public class Shop
{
public virtual Int Id { get; set; };
public virtual string Name { get; set; };
public virtual ISet<Employee> AllEmployees{ get; set; }
public Shop()
{
AllEmployees = new HashedSet<Employee>();
}
}
public class ShopMap: ClassMap<Shop>
{
public ShopMap()
{
Id(x => x.Id);
Map(x => x.Name);
}
HasMany(c => c.AllEmployees).Cascade.None().NotFound.Ignore();
}
public class Employee
{
public virtual Int Id { get; set; };
public virtual string FirstName { get; set; };
public virtual string SureName { get; set; };
public virtual Shop WorksAt{ get; set; }
public Employee()
{
}
}
public class EmployeeMap: ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.Id);
Map(x => x.FirstName);
Map(x => x.SureName);
References(c => c.WorksAt).Cascade.SaveUpdate().Fetch.Join().NotFound.Ignore();
}
}
更新
这是存储库基类中我的Save()方法的代码:
public static void Save(T pSaveObj)
{
using (ISession session = GetSession())
{
using (ITransaction trans = session.BeginTransaction())
{
// session.Save(pSaveObj);
session.Save(session.Merge(pSaveObj));
session.Flush();
session.Clear();
}
}
}
答案 0 :(得分:0)
嗯..你完全误用了NHibernate。 Clear和Flush几乎从未在会话中被调用。创建会话只是为了执行保存,从第一级缓存中获益0。在dispose上隐式回滚事务(如果没有提交),所以你什么都不做。
如果我正确地读了你的意图,你宁愿喜欢这样的代码:
public static void Save(T pSaveObj)
{
using (ISession session = GetSession())
{
using (ITransaction trans = session.BeginTransaction())
{
session.SaveOrUpdate(pSaveObj);
trans.Commit()
}
}
}
P.S。看看NH正在使用sql profiler做什么。我发现这是一种很好的学习方式。