非法尝试将一个集合与两个打开的会话关联
本文关键字:两个 关联 会话 一个 集合 非法 | 更新日期: 2023-09-27 18:15:54
我有这个异常"非法尝试将一个集合与两个打开的会话关联",每次我保存包含子集合的实体时都会引发这个异常。我谷歌一下。我发现我在调用save时打开了两个或更多的会话,但我确信我只使用了一个会话。我哪里做错了?我该如何解决这个问题?注意:我正在使用MVC4,和流利的NHibernate。
实体:
public class Employee : EntityBase<int>
{
public Employee()
: base()
{
Phones = new List<Phone>();
}
public Employee(int id) : this() { Id = id; }
[Browsable(false)]
public override ApprovalBase Approval
{
get;
set;
}
public virtual string Name { get; set; }
public virtual string Job { get; set; }
[Browsable(false)]
public virtual IList<Phone> Phones { get; set; }
}
public class Phone : EntityBase<int>
{
public Phone()
: base()
{
}
public Phone(int id) : this() { Id = id; }
public override ApprovalBase Approval
{
get;
set;
}
public virtual string PhoneNumber { get; set; }
public virtual string PhoneType { get; set; }
public virtual int EmployeeId { get; set; }
public virtual Employee Employee { get; set; }
}
映射:
public sealed class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Table("dbo.Employee");
Id(x => x.Id).Column("EmployeeId");
Map(x => x.Name);
Map(x => x.Job);
HasMany(x => x.Phones).KeyColumn("EmployeeId").Table("dbo.Phone").Cascade.All().Inverse();
}
}
public sealed class PhoneMap : ClassMap<Phone>
{
public PhoneMap()
{
Table("dbo.Phone");
Id(x => x.Id).Column("PhoneId");
Map(x => x.PhoneNumber);
Map(x => x.PhoneType);
Map(x => x.EmployeeId);
References(x => x.Employee).Column("EmployeeId")
.Not.Update()
.Not.Insert();
}
}
存储库:
public abstract class RepositoryBase<TEntity, TIdentity>
: IRepository<TEntity, TIdentity>
where TEntity : EntityBase<TIdentity>
where TIdentity : IComparable
{
private readonly IPersistor<TEntity, TIdentity> persistor; //contains the session to operate with the database
public IPersistor<TEntity, TIdentity> Persistor { get { return persistor; } }
private readonly IFinder<TEntity, TIdentity> finder;
public IFinder<TEntity, TIdentity> Finder { get { return finder; } }
private RepositoryBase() { }
public RepositoryBase(
IPersistor<TEntity, TIdentity> persistor,
IFinder<TEntity, TIdentity> finder)
{
this.persistor = persistor;
this.finder = finder;
this.finder.DataSource = Query();
}
// Get entity by ID
public virtual TEntity Get(TIdentity id)
{
return persistor.Get(id);
}
/// <summary>
/// Validate and Save the entity. If the validation failed, will not save the entity,
/// but returns back list of error messages.
/// </summary>
public virtual IList<String> Save(TEntity entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
IList<String> errors = entity.Validate();
if (errors.Count == 0)
{
persistor.Save(entity);
}
return errors;
}
// Delete entity from persistance repository
public virtual void Delete(TIdentity id)
{
persistor.Delete(id);
}
/// Gets IQueryable which we use from the concrete
/// implementation of repository to implement our
/// query methods (FindBy).
protected IQueryable<TEntity> Query()
{
return persistor.Query();
}
public IList<TEntity> GetAll()
{
return persistor.Query().ToList();
}
}
public class EmployeeRepository : RepositoryBase<Employee, int>, IEmployeeRepository
{
public EmployeeRepository(
IPersistor<Employee, int> persistor,
IEmployeeFinder entityFinder)
: base(persistor, entityFinder) { }
public IEmployeeFinder Find
{
get { return (IEmployeeFinder)Finder; }
}
}
public class PhoneRepository : RepositoryBase<Phone, int>, IPhoneRepository
{
public PhoneRepository(
IPersistor<Phone, int> persistor,
IPhoneFinder entityFinder)
: base(persistor, entityFinder) { }
public IPhoneFinder Find
{
get { return (IPhoneFinder)Finder; }
}
}
在填写完员工的所有信息并添加电话集合后,当我按下保存键时,这些信息还没有保存到数据库中。经过一些调试,我发现当我的程序到达"Session.SaveOrUpdate(entity);"时,出现了上面的异常。如何解决这个问题?
另外,为了完整起见,通常有两种类型的问题:
-
通常与使用自己的
ISession
创建的不正确管理的DAO对象相关:在上面定义的示例中,可以有两个对象与存储库一起工作:(a)
persistor
和(b)finder
。它们各有一个
ISession
实例。如果finder
成功并找到一些东西(例如Phones),则请求它们的实体Employee
尝试保存,但是Phones位于与Employee不同的会话中。 -
通常与ASP相关。. NET MVC及其
Redirect()
动作结果:最有可能的手机由不同的会话加载。而不是处理Employee的"current"。
所以最可疑的是调用
Redirect()
。如果是,我们在一个控制器生命周期中加载对象-将其放入Temp字典-调用重定向到另一个控制器 -现在有一个新会话以及与旧的关闭会话关联的旧对象。
解决方案:确保所有DAO处理都是一个ISession
作用域的一部分。不要在会话之间传输任何数据(也不要在控制器重定向之间)…
我在使用静态变量的每个方法中使用锁语句来解决这个问题,因为问题的根源与同步有关。
下面是一个简单的例子来说明我的解决方案:
private static int sharedVariable;
private static object _syncronizationObject = new Object();
public void MethodThatUsesStaticVariable(int newValue)
{
// This lock prevents concurrency problems, and this is what solved the issue for me.
lock(_syncronizationObject)
{
sharedVariable = newValue;
}
}