Pergunta

Estou usando o NHibernate para um tempo e agora têm encontrado ao longo do tempo que se eu tentar pedir duas páginas simultaniously (ou tão perto como eu posso) que irá ocasionalmente erro. Então eu assumi que era porque a minha gestão Session não foi o segmento de seguros.

Eu pensei que era minha classe, então eu tentei usar um método diferente a partir deste post http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/ entretanto eu ainda obter os mesmos problemas. O erro real que eu estou recebendo é:

Server Error in '/AvvioCMS' Application.
failed to lazily initialize a collection, no session or session was closed
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: NHibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed

Ou isso ou não datareader está aberto, mas este é o principal culpado.

Eu coloquei minha classe de gerenciamento de sessões abaixo, alguém pode ponto por isso que eu pode estar tendo essas questões?

public interface IUnitOfWorkDataStore
{
    object this[string key] { get; set; }
}


    public static Configuration Init(IUnitOfWorkDataStore storage, Assembly[] assemblies)
    {
        if (storage == null)
            throw new Exception("storage mechanism was null but must be provided");

        Configuration cfg = ConfigureNHibernate(string.Empty);
        foreach (Assembly assembly in assemblies)
        {
            cfg.AddMappingsFromAssembly(assembly);
        }

        SessionFactory = cfg.BuildSessionFactory();
        ContextDataStore = storage;

        return cfg;
    }

    public static ISessionFactory SessionFactory { get; set; }
    public static ISession StoredSession
    {
        get
        {
            return (ISession)ContextDataStore[NHibernateSession.CDS_NHibernateSession];
        }
        set
        {
            ContextDataStore[NHibernateSession.CDS_NHibernateSession] = value;
        }
    }

    public const string CDS_NHibernateSession = "NHibernateSession";
    public const string CDS_IDbConnection = "IDbConnection";

    public static IUnitOfWorkDataStore ContextDataStore { get; set; }

    private static object locker = new object();
    public static ISession Current 
    {
        get 
        {
            ISession session = StoredSession;

            if (session == null) 
            {
                lock (locker)
                {
                    if (DBConnection != null)
                        session = SessionFactory.OpenSession(DBConnection);
                    else
                        session = SessionFactory.OpenSession();

                    StoredSession = session;
                }
            }

            return session;
        }
        set
        {
            StoredSession = value;
        }
    }

    public static IDbConnection DBConnection
    {
        get
        {
            return (IDbConnection)ContextDataStore[NHibernateSession.CDS_IDbConnection];
        }
        set
        {
            ContextDataStore[NHibernateSession.CDS_IDbConnection] = value;
        }
    }

}

E a loja real que estou usando é o seguinte:

public class HttpContextDataStore : IUnitOfWorkDataStore
{
    public object this[string key]
    {
        get { return HttpContext.Current.Items[key]; }
        set { HttpContext.Current.Items[key] = value; }
    }
}

Eu inicializar o SessionFactory em Application_Start com:

NHibernateSession.Init(new HttpContextDataStore(), new Assembly[] { 
                typeof(MappedClass).Assembly});

Atualizar

Oi pessoal, obrigado por seu conselho, eu tentei algumas coisas diferentes para tentar simplificar o código, mas eu ainda estou correndo nos mesmos problemas e que eu possa ter uma idéia do porquê.

Eu criar a sessão por pedido como e quando é necessário, mas no meu global Estou descartar a sessão sobre Application_EndRequest. No entanto eu estou achando o Application_EndRequest está sendo disparados mais de uma vez, enquanto eu estou em debug no final do carregamento de uma página. Eu pensei que o evento só é suposto fogo uma vez no final do pedido, mas se não for e alguns outros itens estão tentando usar a sessão (que é o que o erro está reclamando) por qualquer motivo estranho que pudesse ser meu problema ea sessão ainda é o segmento de seguros que está apenas a ser eliminados para início.

Alguém tem alguma idéia? Eu fiz um google e vi que o servidor de desenvolvimento VS causar problemas como esse, mas estou executando-o através do IIS.

Foi útil?

Solução

Embora eu não tenha visto toda a sua base de código ou o problema que você está tentando resolver, repensar como você está usando NHibernate pode estar em ordem. Do documentação :

Você deve observar o seguinte práticas ao criar NHibernate Sessões:

  • Nunca crie mais de um concorrente ISession ou ITransaction por exemplo banco de dados de conexão.

  • Tenha muito cuidado ao criar mais do que uma base de dados por ISession por transação. O ISession si mantém o controle de atualizações feitas para carregado objetos, de modo a poder ISession diferente veja dados obsoletos.

  • O ISession é não threadsafe! Never acessar o mesmo ISession em dois threads simultâneos. Um ISession é geralmente apenas um única unidade-de-obra !

Essa última parte é a mais relevante (e importante no caso de um ambiente multithreaded) para o que estou dizendo. Um ISession deve ser usado uma vez para uma pequena operação atómica e, em seguida, descartado. Também a partir da documentação:

Um ISessionFactory é um cara-a-criar, objeto threadsafe destina a ser compartilhada por todos threads da aplicação. Um ISession é um barato, objecto não-multitarefa que deve ser usado uma vez, por uma única processos de negócios, e depois descartado.

Combinando essas duas idéias, em vez de armazenar o próprio ISession, armazenar a fábrica de sessão uma vez que é o "grande" objeto. Você pode, então, empregar algo como SessionManager.GetSession () como um wrapper para recuperar a fábrica a partir do armazenamento de sessão e instanciar uma sessão e usá-lo para uma operação.

O problema também é menos óbvia no contexto de uma aplicação ASP.NET. Você está escopo estaticamente o objeto ISession que significa que é compartilhado entre o AppDomain. Se dois pedidos de página diferentes são criados dentro desse tempo de vida de AppDomain e são executadas simultaneamente, agora você tem duas páginas (tópicos diferentes) tocando a mesma ISession que é não seguro.

Basicamente, em vez de tentar manter uma sessão em torno de tanto tempo quanto possível, tentar se livrar deles o mais rápido possível e veja se você tem melhores resultados.

EDIT:

Ok, eu posso ver onde você está tentando ir com este. Parece que você está tentando implementar o padrão Sessão Aberta em vista, e há um par de diferentes rotas que você pode assumir que:

Se a adição de um outro quadro não é um problema, olhar para algo como Spring.NET . É modular para que você não tem que usar a coisa toda, você pode simplesmente usar o módulo auxiliar NHibernate. Ele suporta a sessão aberta no modo padrão. Documentação aqui (posição 21.2.10. "Gerenciamento de sessão Web" ).

Se você prefere rolar o seu próprio, confira esta postagem codeproject por Bill McCafferty: "NHibernate Melhores Práticas" . Perto do final ele descreve implementar o padrão através de um IHttpModule personalizado. Eu também vi mensagens em torno da Internet para implementar o padrão sem um IHttpModule, mas que pode ser o que você está tentando.

O meu padrão habitual (e talvez você já saltou à frente aqui) é usar uma estrutura em primeiro lugar. Ele remove muita dor de cabeça. Se for muito lenta ou não se encaixa as minhas necessidades, então eu tentar ajustar a configuração ou personalizá-lo. Só depois que eu tento fazer a minha própria, mas YMMV. :)

Outras dicas

Eu não posso estar certo (como eu sou um cara de Java Hibernate) em NHibernate mas em hibernação objetos de sessão não são segmento seguro por design. Você deve abrir e fechar uma sessão e nunca permitir que ele fora do escopo do segmento atual.

Eu tenho certeza que os padrões tais como 'Open vista sessão' têm sido implementadas em .Net em algum lugar.

A outra questão interessante é quando você coloca uma entidade de hibernação na sessão. O problema aqui é que a sessão que está ligado à será fechada (ou deveria ser) sobre o acabamento pedido. Você tem que volte a colocar a entidade para a nova sessão (hibernate) se você deseja navegar todas as associações não carregados. Este na auto faz com que um novo problema se duas solicitações tentar fazer isso ao mesmo tempo como algo vai explodir se você tentar anexar uma entidade para duas sessões.

Espero que isso ajude. Gareth

O problema acabou sendo que a minha biblioteca para inversão de controle não foi gerir os objetos que estão sendo criadas em HTTP contexto corretamente assim que eu estava ficando referências para objetos que de não estiveram disponíveis para esse contexto. Este foi usando Ninject 1.0, uma vez que eu atualizado para Ninject 2.0 (beta) o problema foi resolvido.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top