NHibernate Lazy Initialization创建新的会话

时间:2016-12-08 18:38:26

标签: c# .net sql-server nhibernate fluent-nhibernate

我看到NHibernate在迭代一个有点深的对象图时抛出一个LazyInitializationException。我假设我对NHibernate的工作方式存在误解;你能解释我哪里出错吗?

public class CustomerSummary {
    public virtual ISet<House> Houses { get; set; } = new HashSet<House>()
}

public class House {
    public virtual ISet<Feed> Feeds { get; set; } = new HashSet<Feed>()
}

public class Feed {
    public virtual int Id { get; set; }
    public virtual int OtherId { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual ISet<Charge> Charges { get; set; } = new HashSet<Charge>()
}

public class Charge {
    public virtual int Id { get; set; }
    public virtual int OtherId { get; set; }
    public virtual decimal Amount { get; set; }
}

查询

public IEnumerable<CustomerSummary> GetAll()
{   
    CustomerSummary cs = null;
                    House h = null;
                    Feed f = null;
                    var query = Session.QueryOver(() => cs)
                                       .JoinAlias(() => cs.Houses, () => h, JoinType.LeftOuterJoin)
                                       .JoinAlias(() => h.Feeds, () => f, JoinType.LeftOuterJoin,
                                           Restrictions.Eq(nameof(Feed.Date), month));

    var results = query.TransformUsing(Transformers.DistinctRootEntity)
                       .Future();

    return results;
}

导致例外的代码

public void GenerateInvoices()
{
    var summaries = m_Repository.GetAll();
    foreach (var summary in summaries) {
        foreach (var house in summary.Houses) {
            foreach (var feed in house.Feeds) {
                //Exception here on Charges iterator, but only on the 2nd CustomerSummary entity. 
                foreach (var charge in feed.Charges) { 
                }
            }
        }
    }
}

在NHibernate Profiler中,我可以看到第二个会话被创建导致LazyInitializationException:

NHibernateProfiler

如果您需要信息,我会更新问题。提前感谢您的回答!

编辑:

我包括我怀疑可能导致问题的相关映射。请注意用于将2个表连接在一起的 OtherId ,而不是主键。不同的CustomerSummaries或Houses可能会引用相同的Charge实体。

public class FeedMap : ClassMap<Feed> {
    public FeedMap()
    {            
        Id(x => x.Id).Column("Feed_Id");
        Map(x => x.Date).Column("Feed_Date");
        Map(x => x.OtherId).Column("Other_Id");                      

        References(x => x.House).Column("House_Id");

        HasMany(x => x.Charges)
            .PropertyRef(nameof(Charge.OtherId))
            .KeyColumn("Other_Id");
    }
}

编辑2:

添加Repository / SessionContext的实现。

我通过Fluent NHibernate配置Context,如下所示:

.ExposeConfiguration(x => x.SetProperty("current_session_context_class", "thread_static"));

和...

public abstract class Repository {
    protected ISessionFactory SessionFactory { get; }

    protected ISession Session {
        get {
            if (CurrentSessionContext.HasBind(SessionFactory)) {
                return SessionFactory.GetCurrentSession();
            }

            var session = SessionFactory.OpenSession();                             
            session.FlushMode = FlushMode.Never;

            var stackTrace = new StackTrace();
            var frames = stackTrace.GetFrames();
            var sessionName = stackTrace.GetFrame(1).GetMethod().Name;

            if (frames != null) {
                foreach (var frame in frames) {
                    if (frame.GetMethod().Module.Assembly.GetName().Name != Assembly.GetExecutingAssembly().GetName().Name) {
                        sessionName = frame.GetMethod().Name;
                        break;
                    }
                }
            }

            HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.RenameSessionInProfiler(session, sessionName);

            CurrentSessionContext.Bind(session);
            return session;
        }
    }

    protected Repository(ISessionFactory sessionFactory)
    {
        if (sessionFactory == null) {
            throw new ArgumentNullException(nameof(sessionFactory));
        }
        SessionFactory = sessionFactory;
    }
}

0 个答案:

没有答案