Hi all,
I have this exception "illegal attempt to associate a collection with two open sessions", it raises every time I save entity contains collection of children.
I google it. I found that I opened two or more sessions when calling save, but I'm sure that I'm using only one session.
Where I did wrong? How can I solve this problemn?
Note: I'm using MVC4, and fluent NHibernate.
Entities:
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; }
}
Mapping:
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();
}
}
Repository:
public interface IPersistor<TEntity, TIdentity>
{
TEntity Get(TIdentity id);
void Save(TEntity entity);
void Delete(TIdentity id);
IQueryable<TEntity> Query();
}
public interface IRepository<TEntity, TIdentity>
where TEntity : EntityBase<TIdentity>
where TIdentity : IComparable
{
IList<TEntity> GetAll();
TEntity Get(TIdentity id);
IList<String> Save(TEntity entity);
void Delete(TIdentity id);
}
public abstract class RepositoryBase<TEntity, TIdentity>
: IRepository<TEntity, TIdentity>
where TEntity : EntityBase<TIdentity>
where TIdentity : IComparable
{
private readonly IPersistor<TEntity, TIdentity> persistor;
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();
}
public virtual TEntity Get(TIdentity id)
{
return persistor.Get(id);
}
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;
}
public virtual void Delete(TIdentity id)
{
persistor.Delete(id);
}
protected IQueryable<TEntity> Query()
{
return persistor.Query();
}
public IList<TEntity> GetAll()
{
return persistor.Query().ToList();
}
}
Persistor
public abstract class PersistorBase<TEntity, TIdentity>
: IPersistor<TEntity, TIdentity>
{
protected ISession Session { get; set; }
public PersistorBase(ISession session)
{
Session = session;
}
public TEntity Get(TIdentity id)
{
return (TEntity)Session.Get(typeof(TEntity), id);
}
public void Save(TEntity entity)
{
try
{
Session.SaveOrUpdate(entity);
NhUnitOfWork.Current.Commit();
}
catch
{
NhUnitOfWork.Current.Rollback();
}
}
public void Delete(TIdentity id)
{
try
{
Session.Delete(Session.Load<TEntity>(id));
NhUnitOfWork.Current.Commit();
}
catch
{
NhUnitOfWork.Current.Rollback();
}
}
public IQueryable<TEntity> Query()
{
var qry = from t in Session.Query<TEntity>()
select t;
return qry.AsQueryable();
}
}
Session factory:
public abstract class BaseDatabase : IDisposable
{
protected static Configuration configuration;
protected static ISessionFactory sessionFactory;
public ISession Session { get; protected set; }
protected void Init()
{
sessionFactory = CreateSessionFactory();
NhUnitOfWork.Current = new NhUnitOfWork(sessionFactory);
NhUnitOfWork.Current.BeginTransaction();
Session = NhUnitOfWork.Current.Session;
}
protected abstract ISessionFactory CreateSessionFactory();
public void Dispose()
{
Session.Dispose();
}
}
MVC4 controller:
[ValidateInput(false)]
public class EmployeeController : BaseController
{
private IEmployeeRepository EmployeeR;
public override void Init()
{
EmployeeR = new EmployeeRepository(new EmployeePersistor(db.Session), new EmployeeFinder());
}
...
[HttpPost]
public ActionResult Edit(Employee employee)
{
try
{
if (ModelState.IsValid)
{
employee.Phones = (IList<Phone>)Session["Phones"];
IList<string> errors = EmployeeR.Save(employee);
Session["Phones"] = null;
return RedirectToAction("Index");
}
}
catch (Exception ex)
{
}
return PartialView(employee);
}
...
}
After I fill all the information of the Employee and add collection of phones, when I press save, the information haven't been saved in the database. After some debugging, I found that when my program reaches to "Session.SaveOrUpdate(entity);" the exception above appeared.
How to solve this issue?