【问题标题】:Fluent NHibernate List of objects exceptionFluent NHibernate 对象列表异常
【发布时间】:2014-01-30 00:43:54
【问题描述】:

我有一个 DAL,使用 Fluent NHibernate 来映射查询(作为字符串存储在 db 中)及其参数(存储在单独的表中)。

当我尝试在服务层中使用这个参数列表时,我遇到了问题。

List<QueryParameter> lqp = (List<QueryParameter>)qry.parameters;

投掷

无法转换 Hibernate.Collection.Generic.PersistentGenericBag1[nha.cs.utility.mole.QueryParameter]' to type 'System.Collections.Generic.List1 [nha.cs.utility.mole.QueryParameter]' 类型的对象。


List<QueryParameter> lqp = qry.parameters.ToList<QueryParameter>();

投掷

Initializing[nha.cs.utility.mole.Query#24] - 无法延迟初始化角色集合:nha.cs.utility.mole.Query.parameters,没有会话或会话已关闭


List<QueryParameter> lqp = new List<QueryParameter>(qry.parameters);

投掷

测试方法 MoleSVSTest.MoleSVCTester.MoleSVCTestMethod 抛出异常: NHibernate.LazyInitializationException:
Initializing[nha.cs.utility.mole.Query#24] - 无法延迟初始化角色集合:nha.cs.utility.mole.Query.parameters,没有会话或会话已关闭


IList<QueryParameter> lqp = (IList<QueryParameter>)qry.parameters;

投掷

测试方法 MoleSVSTest.MoleSVCTester.MoleSVCTestMethod 抛出异常: NHibernate.LazyInitializationException: Initializing[nha.cs.utility.mole.Query#24]-未能延迟初始化角色集合:nha.cs.utility.mole.Query.parameters,没有会话或会话已关闭

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<QueryParameter> parameters { get; set; }
    public virtual IList<Application> applicationsUsedIn { get; set; }

    public Query()
    {
        this.parameters = new List<QueryParameter>();
        this.applicationsUsedIn = new List<Application>();
    }

    public virtual void AddParameter(QueryParameter qp)
    {
        qp.query = this;
        this.parameters.Add(qp);
    }
}


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()
            .KeyColumn("qryid")
            .LazyLoad()
            ;
        HasManyToMany(x => x.applicationsUsedIn)
            .Table("dbo.ApplicationsQueries")
            .ParentKeyColumn("qryid")
            .ChildKeyColumn("appid")
            .Inverse()
            .LazyLoad()
            ;
    }
}


    public XmlNode runQuery(string appnname, string qryname, List<String> parms)
    {
        XmlNode xn = null;

        if ((null != appnname) && (appnname.Length > 0))
        {
            if ((null != qryname) && (qryname.Length > 0))
            {
                Query qry = md.getQuery(appnname, qryname);
                if (null != qry)
                {
                    if ((null != parms) && (parms.Count > 0)) //Passed parameters as List<String>
                    {
                        //These are the three lines I have tried
                        IList<QueryParameter> lqp = (IList<QueryParameter>)qry.parameters;
                        List<QueryParameter> lqp = qry.parameters.ToList<QueryParameter>();
                        List<QueryParameter> lqp = new List<QueryParameter>(qry.parameters);
    ...
    ...
    ...


更新了 QueryParameter 类和地图。

public class QueryParameter
{
    public virtual int id { get; set; }
    public virtual Query query { get; set; }
    public virtual string name { get; set; }
    public virtual MOLEDataTypes type { get; set; }
    public virtual int order { get; set; }

    public QueryParameter()
    {
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;
        var t = obj as QueryParameter;
        if (t == null)
            return false;
        if (query == t.query && name == t.name)
            return true;
        return false;
    }

    public override int GetHashCode()
    {
        return (query.id + "|" + name).GetHashCode();
    }
}


public class QueryParametersMap : ClassMap<QueryParameter>
{
    public QueryParametersMap()
    {
        Table("dbo.QueryParameters");
        Id(x => x.id);
        References(x => x.query).Column("qryid").Not.Insert();
        Map(x => x.name);
        Map(x => x.type).CustomType<MOLEDataTypes>();
        Map(x => x.order).Column("ordr");
    }
}

更多代码

    public Query getQuery(string appname, string qryname)
    {
        Query retq = null;

        using (ISessionFactory isf = getSessionFactory())
        {
            using (var sess = isf.OpenSession())
            {
                using (var tran = sess.Transaction)
                {
                    try
                    {
                        tran.Begin();
                        ...
                        USING session
                        ...
                    }
                    catch (Exception ex)
                    {
                        tran.Rollback();
                        sess.Close();
                        lws.logMessage(AppName, "getQuery", ex.ToString(), MessageType.Error, MessageLevel.Error);
                    }
                }
            }
        }

        return (retq);
    }

您可能有任何提示或建议将不胜感激。

谢谢,

布鲁斯。

【问题讨论】:

  • 您使用的是哪个版本的 NHibernate?您能否也提供QueryParameter 的实体/映射?
  • 我按照你的建议添加了课程。
  • 其实没必要。我不确定我在想什么。无论如何,我相信你的问题在于你的会话。致电md.getQuery() 时是否关闭/清除会话?还是您将getQuery() 方法包装在using (session) 块中?如果是这样,那么这很可能是您的错误的原因。看看这个问题:stackoverflow.com/questions/1893611/…
  • 我正在使用 DAL 级别的会话,在 getQuery 方法中打开和关闭。您是说我需要在使用 getQuery 方法的结果期间保持该会话打开。这是一个查询对象。
  • 我添加了 getQuery 方法。我在这里使用会话的方式不正确吗?

标签: c# nhibernate fluent-nhibernate


【解决方案1】:

问题是您关闭了getQuery 中的会话,然后询问您的Query 对象的参数列表,NHibernate 尝试加载该对象,但由于缺少会话而失败。要解决您的问题,您需要确保您的会话在整个请求期间处于打开状态,或者至少在所有业务事务完成之前保持打开状态。

我建议您采用按请求会话的方法。每当有网络请求时打开一个会话,并在会话结束时关闭它。这可以通过使用 Global.asax 文件轻松实现,您可以阅读有关 here 的信息。

public class Global : System.Web.HttpApplication
{    
    public static ISessionFactory SessionFactory { get; private set; }  

    protected void Application_Start(object sender, EventArgs e)
    {
        // Create a session factory when the application starts.
        // Session factories are expensive to create, and therefore you should create one and use it throughout your application.
        SessionFactory = Fluently.Configure()
                                 .Database(
                                    SQLiteConfiguration.Standard
                                        .UsingFile("firstProject.db")
                                 )
                                 .BuildSessionFactory();
    }

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        // Create a session per request.
        var session = SessionFactory.OpenSession();
        CurrentSessionContext.Bind(session);
    }

    protected void Application_EndRequest(object sender, EventArgs e)
    {
        // Close the session at the end of every request
        var session = CurrentSessionContext.Unbind(SessionFactory);
        session.Dispose();
    }

    protected void Application_End(object sender, EventArgs e)
    {
        // Close the session factory at the end of the application.
        if (SessionFactory != null)
            SessionFactory.Dispose();
    }
}

在上面的示例中,在应用程序启动时创建了会话工厂,建议这样做,因为创建会话工厂的成本很高。然后,每个请求都会创建一个会话,并在最后处理。通过使用这种方法,您可以为自己节省大量工作,因为一切都是自动完成的。

然后,要在代码中使用会话,您只需调用 GetCurrentSession(),如下所示:

var session = Global.SessionFactory.GetCurrentSession();

我希望这会有所帮助,并祝你在 NHibernate 上好运。我建议您考虑阅读 NHibernate 3.0 Cookbook 以更好地了解 NHibernate。

【讨论】:

  • 非常感谢您的帮助。你是对的。一旦我更改了代码以在服务层中创建和维护会话,问题就解决了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-11
  • 2011-02-06
  • 2013-11-22
  • 2011-10-26
  • 2010-10-06
  • 2014-01-24
相关资源
最近更新 更多