更新实体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个DAO创建您的图片对象,并使用不同的DAO更新Post。你的NHibernate助手只是在每次请求Session时分发新的Session。您希望每个web请求共享相同的会话。
我将放弃整个NHibernateHelper的概念,只是对你的Global.asax进行更改。
看我的答案在这里
但归根结底是
- 在Application_Start中创建SessionFactory,将其存储在Global.asax的静态属性中
- 创建一个当前会话属性,映射到HttpContext中的一个项。Application_BeginRequest打开会话
- 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
}