I get this error:
a different object with the same
identifier value was already
associated with the session: 63, of
entity: Core.Domain.Model.Employee
Within my ASP.NET MVC controller actions I do this:
public ActionResult Index(int? page)
{
int totalCount;
Employee[] empData = _employeeRepository.GetPagedEmployees(page ?? 1, 5, out totalCount);
EmployeeForm[] data = (EmployeeForm[]) Mapper<Employee[], EmployeeForm[]>(empData);
PagedList<EmployeeForm> list = new PagedList<EmployeeForm>(data, page ?? 1, 5, totalCount);
if (Request.IsAjaxRequest())
return View("Grid", list);
return View(list);
}
public ActionResult Edit(int id)
{
ViewData[Keys.Teams] = MvcExtensions.CreateSelectList(
_teamRepository.GetAll().ToList(),
teamVal => teamVal.Id,
teamText => teamText.Name);
return View(_employeeRepository.GetById(id) ?? new Employee());
}
[HttpPost]
public ActionResult Edit(
Employee employee,
[Optional, DefaultParameterValue(0)] int teamId)
{
try
{
var team = _teamRepository.GetById(teamId);
if (team != null)
{
employee.AddTeam(team);
}
_employeeRepository.SaveOrUpdate(employee);
return Request.IsAjaxRequest() ? Index(1) : RedirectToAction("Index");
}
catch
{
return View();
}
}
Mapping files:
Employee
public sealed class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(p => p.Id)
.Column("EmployeeId")
.GeneratedBy.Identity();
Map(p => p.EMail);
Map(p => p.LastName);
Map(p => p.FirstName);
HasManyToMany(p => p.GetTeams())
.Access.CamelCaseField(Prefix.Underscore)
.Table("TeamEmployee")
.ParentKeyColumn("EmployeeId")
.ChildKeyColumn("TeamId")
.LazyLoad()
.AsSet()
.Cascade.SaveUpdate();
HasMany(p => p.GetLoanedItems())
.Access.CamelCaseField(Prefix.Underscore)
.Cascade.SaveUpdate()
.KeyColumn("EmployeeId");
}
}
Team:
public sealed class TeamMap : ClassMap<Team>
{
public TeamMap()
{
Id(p => p.Id)
.Column("TeamId")
.GeneratedBy.Identity();
Map(p => p.Name);
HasManyToMany(p => p.GetEmployees())
.Access.CamelCaseField(Prefix.Underscore)
.Table("TeamEmployee")
.ParentKeyColumn("TeamId")
.ChildKeyColumn("EmployeeId")
.LazyLoad()
.AsSet()
.Inverse()
.Cascade.SaveUpdate();
}
}
How do I fix this bug and what is the problem here?
You are most probably adding two employees with the same id to the session.
Find the reason why there are two employees with the same id.
Are you using detached (e.g. serialized) entities? You most probably have the entity loaded from the database (eg. when loading the team) and another which is detached and gets added. The best you can do is not using the detached instance at all. Only use its id to load the real instance from the database:
When you want to write the values in the
detachedEmployeeover the employee in the session, usesession.Mergeinstead ofsession.Update(orsession.SaveOrUpdate):There are other reasons for this error, but I don’t know what you are doing and how your mapping file looks like.
Edit
This should work:
Or use merge:
Explanation:
There could only be one instance of the same database “record” in memory. NH ensures that the same instance is returned by a query as already is in the session cache. If it wouldn’t be like this, there would be more than one value in memory for the same database field. This would be inconsistent.
Entities are identified by their primary key. So there must be only one instance per primary key value. Instances are put into the session by queries, Save, Update, SaveOrUpdate or Lock.
You get a problem when an instance is already in the session (eg. by a query) and you try to put another instance (eg. a detached / serialized one) with the same id into the session (eg. using update).
Solution one puts the instance into the session before any other query. NH will return exactly this instance in all subsequent queries! This is really nice, but you need to call Update before any query to make it work properly.
Solution two uses Merge. Merge does the following:
At the end, Merge does never have a problem with already existing instances. It does not even matter if the instance is already in the database or not. You just need to take into account that the return value is the instance in the session, not the argument.
Edit: the second Employee instance