fluentnhibernate有许多相同标识符异常

fluentnhibernate有许多相同标识符异常,nhibernate,fluent-nhibernate,fluent-nhibernate-mapping,Nhibernate,Fluent Nhibernate,Fluent Nhibernate Mapping,我有一个多对多的关系,两个对象之间的应用程序,查询。我已经构建了在两个对象映射中都有HasManyToMany映射的映射 第一次使用SaveOrUpdate应用程序时,它工作正常,并且条目正确地放置在联接表中 但是,第二次使用它时,我得到了错误:“具有相同标识符的不同对象已与会话关联” 异常在下面显示的addQuery代码的最后几行抛出 这里是实体和地图。如有任何建议,将不胜感激 public class Application { public virtual int id { get

我有一个多对多的关系,两个对象之间的应用程序,查询。我已经构建了在两个对象映射中都有HasManyToMany映射的映射

第一次使用SaveOrUpdate应用程序时,它工作正常,并且条目正确地放置在联接表中

但是,第二次使用它时,我得到了错误:“具有相同标识符的不同对象已与会话关联”

异常在下面显示的addQuery代码的最后几行抛出

这里是实体和地图。如有任何建议,将不胜感激

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);
    }
}
更新代码以防它帮助其他人
这里的问题隐藏在许多打开的会话中,实际上是一个操作。这不是执行此插入/更新的正确方式。我们应该始终将一组相互依赖的操作打包到一个会话、一个事务中

发生的情况是,我们收到的查询如下:

Query qry = getQuery(appname, qryname);
我们有一个对象,它是会话的一部分,刚刚超出范围。qry实例现在已完全填充,因为

它是从数据库加载的现有对象。。。 查看映射时使用的IList应用程序集合的映射为.Not.LazyLoad 对于其他Not.LazyLoad映射也是如此。。。 所以一旦我们进入最后一个事务和它自己的会话。。。我们的物体可能会被大量填充。。。与上次会话中加载的对象具有相同的ID

要快速解决此问题,请执行以下操作:

在操作开始时打开会话 在开始时打开事务 如果有新对象,请仅调用Save 对于通过getQuery检索的对象,在同一会话中运行的getApplication不调用SaveOrUpdate。它们已经在会话中,这就是本例中SaveOrUpdated将它们放在会话中的主要原因 调用transaction.Commit,所有内容都将正确持久化 b在操作结束时关闭会话 注意:我将更改多对多的映射

卸下Not.LazyLoad。懒惰是我们最想要的。。 删除级联,因为它与另一端有关,而与配对表无关。如果这是有意的,那就别管它
我真的很感谢你在这方面的帮助。我做了你建议的改变,还有更多。基本上,我将函数中的所有代码,以及它们自己的会话中的所有代码移到了同一个会话中。如果这有帮助的话,那就太好了。享受NHibernate。。。很好,是的。我希望有一种方法可以将代码分解成函数以供重用,但这实际上使代码更具可读性。Radim,有没有一种方法可以将对象应用程序、会话外的查询保存到另一个会话中以供重用?我知道,通常我会说,我们应该在操作中考虑。有些人在写。。。有些人阅读。它们可以代表一个工作单元。因此,我的做法是,例如,在web中打开请求的会话。。。执行需要的操作,在结束时提交或回滚并关闭会话。在网络之外的其他世界中,我们可以拥有所谓的分离对象。它们必须稍后合并到其他/下一个会话中。请检查:感谢共享更新!干得好
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();
                    }
                }
            }
        }
    }
    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();
                }
            }
        }
    }
Query qry = getQuery(appname, qryname);