I have a many-to-many
relationship between two objects (Application
, Query
). I have constructed the map to have a HasManyToMany mapping in both object maps.
The first time I use the SaveOrUpdate the application, it works fine, and the entry is placed correctly in the join table.
However, the second time I use it, I get the error: 'a different object with the same identifier was already associated with the session'.
The exception is thrown in the last couple of lines of the addQuery code shown below.
Here are the entities and the maps. Any suggestions would be greatly appreciated.
public class Application
{
public virtual int id { get; set; }
public virtual string name { get; set; }
public virtual IList<Query> queries { get; set; }
public Application()
{
this.queries = new List<Query>();
}
public virtual void AddQuery(Query qry)
{
qry.applicationsUsedIn.Add(this);
queries.Add(qry);
}
}
public class Query
{
public virtual int id { get; protected set; }
public virtual string name { get; set; }
public virtual string query { get; set; }
public virtual IList<QueryParameters> parameters { get; set; }
public virtual IList<Application> applicationsUsedIn { get; set; }
public Query()
{
this.parameters = new List<QueryParameters>();
this.applicationsUsedIn = new List<Application>();
}
public virtual void AddParameter(QueryParameters qp)
{
qp.query = this;
this.parameters.Add(qp);
}
}
public class ApplicationMap : ClassMap<Application>
{
public ApplicationMap()
{
Table("dbo.Applications");
Id(x => x.id).Column("id");
Map(x => x.name).Column("name");
HasManyToMany(x => x.queries)
.Table("dbo.ApplicationsQueries")
.ParentKeyColumn("appid")
.ChildKeyColumn("qryid")
.Not.LazyLoad()
.Cascade.SaveUpdate();
}
}
public class QueryMap : ClassMap<Query>
{
public QueryMap()
{
Table("dbo.Queries");
Id(x => x.id);
Map(x => x.name);
Map(x => x.query);
HasMany(x => x.parameters)
.Cascade.All()
.Inverse();
HasManyToMany(x => x.applicationsUsedIn)
.Table("dbo.ApplicationsQueries")
.ParentKeyColumn("qryid")
.ChildKeyColumn("appid")
.Inverse()
.Cascade.SaveUpdate()
.Not.LazyLoad();
}
}
public void addQuery(string appname, string qryname, string qrystr)
{
Application app = getApplication(appname);
if (null == app)
{
app = addApplication(appname);
}
Query qry = getQuery(appname, qryname);
if (null == qry)
{
using (ISessionFactory isf = getSessionFactory())
{
using (var sess = isf.OpenSession())
{
using (var tran = sess.Transaction)
{
tran.Begin();
qry = new Query();
qry.name = qryname;
qry.query = qrystr;
sess.Save(qry);
tran.Commit();
}
}
}
}
if (!app.queries.Contains(qry))
{
using (ISessionFactory isf = getSessionFactory())
{
using (var sess = isf.OpenSession())
{
using (var tran = sess.Transaction)
{
tran.Begin();
app.AddQuery(qry);
//This is where the exception is thrown
sess.SaveOrUpdate(app);
tran.Commit();
}
}
}
}
}
UPDATED CODE in case it helps someone else
public ApplicationMap()
{
Table("dbo.Applications");
Id(x => x.id).Column("id");
Map(x => x.name).Column("name");
HasManyToMany(x => x.queries)
.Table("dbo.ApplicationsQueries")
.ParentKeyColumn("appid")
.ChildKeyColumn("qryid")
.LazyLoad();
}
public QueryMap()
{
Table("dbo.Queries");
Id(x => x.id);
Map(x => x.name);
Map(x => x.query);
HasMany(x => x.parameters)
.Cascade.All()
.Inverse();
HasManyToMany(x => x.applicationsUsedIn)
.Table("dbo.ApplicationsQueries")
.ParentKeyColumn("qryid")
.ChildKeyColumn("appid")
.Inverse()
.LazyLoad();
}
public void addQuery(string appname, string qryname, string qrystr)
{
using (ISessionFactory isf = getSessionFactory())
{
using (var sess = isf.OpenSession())
{
using (var tran = sess.Transaction)
{
tran.Begin();
var critapp = sess.CreateCriteria<Application>()
.Add(Restrictions.Eq("name", appname));
Application app = (Application)critapp.UniqueResult();
if (null == app)
{
app = new Application();
app.name = appname;
sess.Save(app);
}
var critqry = sess.CreateCriteria<Query>()
.Add(Restrictions.Eq("name", qryname));
Query qry = (Query)critqry.UniqueResult();
if (null == qry)
{
qry = new Query();
qry.name = qryname;
qry.query = qrystr;
sess.Save(qry);
}
if (!app.queries.Contains(qry))
{
app.AddQuery(qry);
}
tran.Commit();
}
}
}
}