Проблема с настройкой StructureMap/nhibernate:

Я продолжаю получать следующую ошибку:

Не удается получить доступ к удаленному объекту. Имя объекта: «AdoTransaction».

Настройка следует примеру, приведенному на странице http://trason.net/journal/2009/10/7/bootstrapping-nhibernate-with-structuremap.html

вот класс IUnitOfWork (точно такой же, как в ссылке):

public class UnitOfWork : IUnitOfWork
{
    private readonly ISessionFactory _sessionFactory;
    private readonly ITransaction _transaction;

    public UnitOfWork(ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
        CurrentSession = _sessionFactory.OpenSession();
        _transaction = CurrentSession.BeginTransaction();
    }

    public ISession CurrentSession { get; private set; }

    public void Dispose()
    {
        CurrentSession.Close();
        CurrentSession = null;
    }

    public void Commit()
    {
        _transaction.Commit();
    }

}

вот NHibernateModule (опять точно такой же!):

public class NHibernateModule : IHttpModule, IDisposable
{
    private IUnitOfWork _unitOfWork;

    public void Init(HttpApplication context)
    {
        context.BeginRequest += ContextBeginRequest;
        context.EndRequest += ContextEndRequest;
    }

    private void ContextBeginRequest(object sender, EventArgs e)
    {
        _unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>();
    }

    private void ContextEndRequest(object sender, EventArgs e)
    {
        Dispose();
    }

    public void Dispose()
    {
        if (_unitOfWork == null) return;
        _unitOfWork.Commit();
        _unitOfWork.Dispose();
    }
}

вот мой репо:

 public class Repository<T> : IRepository<T>
{
    public readonly IUnitOfWork _uow;

    public Repository(IUnitOfWork uow)
    {
        _uow = uow;
    }

    public Repository()
    {

    }

    #region IRepository<T> Members

    public IList<T> GetAll()
    {
        using (var session = _uow.CurrentSession)
        {
            return session.CreateCriteria(typeof (T)).List<T>();
        }
    }

    public IList<T> FindAll<T>(IList<Expression<Func<T, bool>>> criteria)
    {
        var session = _uow.CurrentSession;

        var query = from item in session.SessionFactory.OpenSession().Query<T>()
                              select item;
        foreach (var criterion in criteria)
        {
            query = query.Where(criterion);
        }
        return query.ToList();
    }

    public T FindFirst<T>(IList<Expression<Func<T, bool>>> criteria)
    {

        var col = FindAll(criteria);

        if (col.Count > 0)
        {
            return col.First();
        }
        else
        {
            return default(T);
        }
    }

    public T Get(int id)
    {
        using (var session = _uow.CurrentSession)
        {
            return session.Get<T>(id);
        }
    }

    public void Save(T entity)
    {
        using (var session = _uow.CurrentSession)
        {
            session.Save(entity);
        }
    }

    public void Update(T entity)
    {
        using (var session = _uow.CurrentSession)
        {
            session.Update(entity);
            session.Flush();
        }
    }

    #endregion
}
}

вот мой загрузчик:

 public class BootStrapper : IBootstrapper
{
    private static bool _hasStarted;

    public virtual void BootstrapStructureMap()
    {
        ObjectFactory.Initialize(x =>
        {
            x.Scan(s =>
            {
                s.TheCallingAssembly();
                s.AssemblyContainingType<User>();
                s.AssemblyContainingType<UserRepository>();
                s.AssemblyContainingType<NHibernateRegistry>();
                s.LookForRegistries();
            });

            // Repositories
            x.For<WmcStar.Data.IUserRepository>()
                .CacheBy(InstanceScope.HttpContext)
                .TheDefault.Is.OfConcreteType<UserRepository>();

            x.For<IDatabaseBuilder>().TheDefaultIsConcreteType<DatabaseBuilder>(); 

        });
    }

    public static void Restart()
    {
        if (_hasStarted)
        {
            ObjectFactory.ResetDefaults();
        }
        else
        {
            Bootstrap();
            _hasStarted = true;
        }
    }

    public static void Bootstrap()
    {
        new BootStrapper().BootstrapStructureMap();
    }

}

вот мой NHibernateRegistry:

public class NHibernateRegistry : Registry
{
    public NHibernateRegistry()
    {
        var cfg = new Configuration()
             .SetProperty(NHibernate.Cfg.Environment.ReleaseConnections, "on_close")
             .SetProperty(NHibernate.Cfg.Environment.Dialect, typeof(NHibernate.Dialect.MsSql2005Dialect).AssemblyQualifiedName)
             .SetProperty(NHibernate.Cfg.Environment.ConnectionDriver, typeof(NHibernate.Driver.SqlClientDriver).AssemblyQualifiedName)
             .SetProperty(NHibernate.Cfg.Environment.ConnectionString, @"my connstring")
             .SetProperty(NHibernate.Cfg.Environment.ProxyFactoryFactoryClass, typeof(ProxyFactoryFactory).AssemblyQualifiedName)
             .AddAssembly(typeof(User).Assembly);

        var sessionFactory = cfg.BuildSessionFactory();

        For<Configuration>().Singleton().Use(cfg);

        For<ISessionFactory>().Singleton().Use(sessionFactory);


        For<ISession>().HybridHttpOrThreadLocalScoped()
            .Use(ctx => ctx.GetInstance<ISessionFactory>().OpenSession());

        For<IUnitOfWork>().HybridHttpOrThreadLocalScoped()
            .Use<UnitOfWork>();

        For<IDatabaseBuilder>().Use<DatabaseBuilder>();
        SetAllProperties(x => x.OfType<IUnitOfWork>());
    }
}

и, наконец, вот мой global.asax:

    public class Global : System.Web.HttpApplication
{

    protected void Application_Start(object sender, EventArgs e)
    {
        BootStrapper.Bootstrap();
        new SchemaExport(ObjectFactory.GetInstance<Configuration>()).Execute(false, true, false);
        ObjectFactory.GetInstance<IDatabaseBuilder>().RebuildDatabase();

        AutoMapper.Mapper.CreateMap<WmcStar.Model.User, WmcStar.Data.Dto.User>();
    }
}

Кто-нибудь получил какие-либо подсказки относительно того, что может вызвать это?

w://


person Community    schedule 27.02.2010    source источник


Ответы (4)


Я не знаю, какая именно проблема вызывает исключение, но я обнаружил некоторые потенциальные проблемы:

  1. Зафиксируйте единицу работы в конце запроса и откатите ее, если фиксация не удалась.
  2. Откат единицы работы, когда во время запроса возникает исключение.
  3. Не вызывайте dispose в конце запроса, это злоупотребляет IDisposable класса.
  4. Удаляйте единицу работы в конце запроса, если она еще не удалена.
  5. Не удаляйте сеанс в каждом методе в вашем репозитории.
  6. Удалите сеанс в методе удаления единицы работы.
  7. Вам не нужно явно закрывать сеанс. достаточно утилизировать.
  8. Удалите транзакцию перед сеансом в методе удаления.
  9. Используйте проверки при удалении метода единицы работы, чтобы предотвратить утечку памяти и сделать сборщик мусора метода удаления надежным.

Набрав этот список, я думаю, что исключение вызвано использованием блоков в репозитории.

Если вам нужно объяснение одной из этих вещей, пожалуйста, спросите меня в комментариях.

person Paco    schedule 27.02.2010
comment
Эй, большое спасибо - я сделал большую часть того, что вы сказали, но в списке: используйте проверки в методе единицы работы, чтобы предотвратить утечку памяти и сделать сборщик мусора методом удаления. Вы можете расширить это? спасибо за отличный ответ :) w:// - person ; 28.02.2010

Я столкнулся с этой проблемой при использовании StructureMap и NHibernate. По сути, у меня есть карта структуры именованного объекта (например, CurrentUser). В этом сопоставлении он использует сеанс NHibernate для извлечения текущего пользователя из базы данных.

Затем где-то в моем коде я делал что-то вроде:

using (var transaction = _session.BeginTransaction())
{
  var user = ObjectFactory.GetNamedInstance<User>("CurrentUser");
  var myObjects = _session.QueryOver<myObject>().Where(x => x.User == CurrentUser).Future();
  transaction.Commit();
}

Ошибка возникает, поскольку транзакция удаляется как часть текущей пользовательской операции. Таким образом, когда выполнение программы достигает строки transaction.Commit(), транзакции для фиксации нет. Мое решение состояло в том, чтобы просто переместить строку пользователя за пределы оператора транзакции:

var user = ObjectFactory.GetNamedInstance<User>("CurrentUser");
using (var transaction = _session.BeginTransaction())
{
  var myObjects = _session.QueryOver<MyObject>().Where(x => x.User == CurrentUser).Future();
  transaction.Commit();
}

Это позволит транзакции вокруг текущего пользовательского поиска быть независимыми от транзакции для MyObject.

person Jim Geurts    schedule 22.03.2010
comment
Спасибо, этот совет сэкономил мне много времени - person suhair; 20.06.2011

Возможно, это не связано с комбинацией StructureMap и NHibernate, а связано с вашим кодом? Я предполагаю, не видя кода, но, скорее всего, вы избавляетесь от транзакции, а затем пытаетесь получить к ней доступ.

person Kent Boogaart    schedule 27.02.2010
comment
Извини, чувак, я действительно сказал, что есть проблема с настройкой nhibernate/structuremap ‹--- SETUP!! - person ; 28.02.2010

Когда я удаляю объект, я столкнулся с тем же сообщением об ошибке. В моих обстоятельствах основной причиной является одно из значений свойства объекта, равное NULL. После того, как я очистил нулевые значения, команда выполнена успешно.

person Jeffery You    schedule 16.03.2018