更新实体1:许多非hibernate

本文关键字:许多非 hibernate 实体 更新 | 更新日期: 2023-09-27 18:03:41

我正试图解决从形式更新实体的问题。我已经为实体Post和Post输入了视图和表单,并收集了图片。

 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>

现在我正试图从输入添加一个图片到这个集合。(所有其他列的更新工作正常)。所以我从输入中获取图片,创建图片对象,持久化它,然后在Post实体的Gallery collection上使用Add(方法)。然后我在post上使用update。但这行不通。它抛出异常: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();
            }
        }
    }
}

更新实体1:许多非hibernate

所以我猜您使用1个DAO创建您的图片对象,并使用不同的DAO更新Post。你的NHibernate助手只是在每次请求Session时分发新的Session。您希望每个web请求共享相同的会话。

我将放弃整个NHibernateHelper的概念,只是对你的Global.asax进行更改。

看我的答案在这里

但归根结底是

  1. 在Application_Start中创建SessionFactory,将其存储在Global.asax的静态属性中
  2. 创建一个当前会话属性,映射到HttpContext中的一个项。Application_BeginRequest打开会话
  3. 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();
            }
        }
    }
}

,我喜欢使用一个通用的存储库来告诉你如何使用在repo之外启动的事务,或者在不存在的情况下创建一个事务。

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
}