Вопрос:

Обновление сущности 1: много nhibernate

c# nhibernate

154 просмотра

1 ответ

35 Репутация автора

Я пытаюсь решить проблему с обновлением сущности из формы. Я набрал вид и форму для сущности Почта и пост имеет коллекцию картинок.

 public class Post : IEntity
    {
        public virtual int Id{ get; set; }

        [Required(ErrorMessage = "Každý článek musí mít titulek")]
        [MaxLength(250, ErrorMessage ="Nadpis může mít maximálně 250 znaků")]
        public virtual string Title { get; set; }
        public virtual string Annotation { get; set; }
        [AllowHtml]
        public virtual string Content { get; set; }
        public virtual User Author { get; set; }
        public virtual DateTime CreationDate { get; set; }
        public virtual Rating Rating { get; set; }
        public virtual string PreviewImageName { get; set; }
        public virtual string ContentImageName { get; set; }
        public virtual Category Category { get; set; }

        public virtual IList<Tag> Tags { get; set; }
        public virtual IList<BlogImage>Gallery { get; set; }
    }

это сопоставлено как один ко многим.

<bag name="Gallery" lazy="true" inverse="true"
                        batch-size="25" cascade="all-delete-orphan">
      <key column="post_id" />
      <one-to-many class="BlogImage" />
    </bag>

Сейчас я пытаюсь добавить картинку из входных данных в эту коллекцию. (Обновление всех остальных столбцов работает просто отлично). Поэтому я беру картинку с ввода, создаю объект Picture, сохраняю его и затем использую Add (метод) в коллекции Gallery на сущности Post. Тогда я использую обновление на пост. Но это не работает. Выдает исключение: HibernateException: недопустимая попытка связать коллекцию с двумя открытыми сеансами. Кто-нибудь может увидеть проблему? Большое спасибо.

public class DaoBase<T> : IDaoBase<T> where T : class, IEntity
    {
        protected ISession session;

        protected DaoBase()
        {
            session = NHibernateHelper.Session;
        }

        public object Create(T entity)
        {
            object o;
            using (ITransaction transaction = session.BeginTransaction())
            {
                o = session.Save(entity);
                transaction.Commit();
            }
            return o;
        }

        public void Delete(T entity)
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Delete(entity);
                transaction.Commit();
            }
        }

        public IList<T> GetAll()
        {
            return session.QueryOver<T>().List<T>();
        }

        public T GetById(int id)
        {
            return session.CreateCriteria<T>().Add(Restrictions.Eq("Id", id)).UniqueResult<T>();
        }

        public void Update(T entity)
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Update(entity);
                transaction.Commit();
            }
        }
    }
}

И код NHibernateHelper по запросу.

namespace DataAccess
{
    public class NHibernateHelper
    {
        private static ISessionFactory _factory;
        public static ISession Session
        {
            get
            {
                if (_factory == null)
                {
                    var cfg = new Configuration();
                    _factory = cfg.Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "hibernate.cfg.xml"))
                        .BuildSessionFactory();
                }
                return _factory.OpenSession();
            }
        }
    }
}
Автор: Pogasta Источник Размещён: 22.08.2016 08:36

Ответы (1)


0 плюса

5463 Репутация автора

Поэтому я собираюсь предположить, что вы создаете объект Picture с помощью 1 DAO и обновляете Post другим DAO. Ваш помощник NHibernate просто раздает новые сеансы каждый раз, когда запрашивается сеанс. Вы хотите использовать один и тот же сеанс для каждого веб-запроса.

Я отказался бы от всей концепции NHibernateHelper и просто сделал бы изменения для вас, Global.asax.

Смотрите мой ответ здесь

Но к чему это сводится

  1. создайте свой SessionFactory в Application_Start, сохранив его в статическом свойстве Global.asax
  2. Создайте свойство текущего сеанса, которое отображается на элемент в HttpContext.
  3. Application_BeginRequest, чтобы открыть сеанс
  4. Application_EndRequest для очистки

Я также хотел бы изменить ваш DAO, чтобы не всегда создавать новую транзакцию. Вы, вероятно, хотите, чтобы все изменения БД, которые вы вносите в одном запросе, были в одной транзакции.

Вот код для атрибута

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TransactionAttribute : ActionFilterAttribute
{
    private ITransaction Transaction { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Transaction = MvcApplication.CurrentSession.BeginTransaction(IsolationLevel.ReadCommitted);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (Transaction.IsActive)
        {
            if (filterContext.Exception == null)
            {
                Transaction.Commit();
            }
            else
            {
                Transaction.Rollback();
            }
        }
    }
}

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

public class Repository<T> : IRepository<T> where T : EntityBase
{
    private readonly ISession _session;

    #region constructor

    public Repository(ISession session)
    {
        _session = session;
    }

    #endregion

    #region Transact

    protected virtual TResult Transact<TResult>(Func<TResult> func)
    {
        if (_session.Transaction.IsActive)
            return func.Invoke();

        TResult result;
        using (var tx = _session.BeginTransaction(IsolationLevel.ReadCommitted))
        {
            result = func.Invoke();
            tx.Commit();
        }

        return result;
    }

    protected virtual void Transact(System.Action action)
    {
        Transact(() =>
        {
            action.Invoke();
            return false;
        });
    }

    #endregion

    #region IRepository<T> Members

    public void Save(T item)
    {
        Transact(() => _session.Save(item));
    }

    public Boolean Contains(T item)
    {
        if (item.Id == default(Guid))
            return false;

        return Transact(() => _session.Get<T>(item.Id)) != null;
    }

    public Int32 Count
    {
        get
        {
            return Transact(() => _session.Query<T>().Count());
        }
    }

    public bool Remove(T item)
    {
        Transact(() => _session.Delete(item));
        return true;
    }

    public T Load(Guid id)
    {
        return Transact(() => _session.Load<T>(id));
    }

    public T Get(Guid id)
    {
        return Transact(() => _session.Get<T>(id));
    }

    public IQueryable<T> FindAll()
    {
        return Transact(() => _session.Query<T>());
    }

    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        return Transact(() => _session.Query<T>().Take(1000).GetEnumerator());
    }

    #endregion

    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator()
    {
        return Transact(() => GetEnumerator());
    }

    #endregion
}
Автор: Fran Размещён: 23.08.2016 05:07
Вопросы из категории :
32x32