Raj*_*Raj 15 linq nhibernate unit-of-work entity-framework-4
我正在开发一个工作单元实现,它在Entity Framework 4.1和NHibernate中都有效.在下面找到我的实现细节的框架
IUnitOfWork定义
public interface IUnitOfWork
{
IRepository<LogInfo> LogInfos { get; }
IRepository<AppInfo> AppInfos { get; }
void Commit();
void Rollback();
}
Run Code Online (Sandbox Code Playgroud)
IRepository定义
public interface IRepository<T> where T : class, IEntity
{
IQueryable<T> FindAll();
IQueryable<T> FindWhere(Expression<Func<T, bool>> predicate);
T FindById(int id);
void Add(T newEntity);
void Remove(T entity);
}
Run Code Online (Sandbox Code Playgroud)
在NHibernate中实现UoW
public class NHibernateUnitOfWork : IUnitOfWork, IDisposable
{
public ISession Session { get; private set; }
public NHibernateUnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
Session = _sessionFactory.OpenSession();
_transaction = Session.BeginTransaction();
}
public IRepository<LogInfo> LogInfos
{
get
{
if (_logInfo == null)
{
_logInfo = new NHibernateRepository<LogInfo>(Session);
}
return _logInfo;
}
}
public void Commit()
{
if (_transaction.IsActive)
_transaction.Commit();
}
}
Run Code Online (Sandbox Code Playgroud)
实体框架4.1中的工作单元
public class SqlUnitOfWork : IUnitOfWork
{
private readonly ObjectContext _context;
public SqlUnitOfWork()
{
_context = new ObjectContext(connectionString);
_context.ContextOptions.LazyLoadingEnabled = true;
}
private SqlRepository<LogInfo> _logInfo = null;
public IRepository<LogInfo> LogInfos
{
get
{
if (_logInfo == null)
{
_logInfo = new SqlRepository<LogInfo>(_context);
}
return _logInfo;
}
}
public void Commit()
{
_context.SaveChanges();
}
}
Run Code Online (Sandbox Code Playgroud)
使用NHibernate的存储库
public class NHibernateRepository<T> : IRepository<T> where T : class, IEntity
{
protected ISession Session;
public NHibernateRepository(ISession session)
{
Session = session;
}
public IQueryable<T> FindAll()
{
return Session.Query<T>();
}
public IQueryable<T> FindWhere(Expression<Func<T, bool>> predicate)
{
return Session.Query<T>().Where<T>(predicate);
}
public T FindById(int id)
{
return Session.Get<T>(id);
}
public void Add(T newEntity)
{
Session.Save(newEntity);
}
public void Remove(T entity)
{
Session.Delete(entity);
}
}
Run Code Online (Sandbox Code Playgroud)
使用实体框架的存储库
public class SqlRepository<T> : IRepository<T> where T : class, IEntity
{
protected ObjectSet<T> ObjectSet;
public SqlRepository(ObjectContext context)
{
ObjectSet = context.CreateObjectSet<T>();
}
public IQueryable<T> FindAll()
{
return ObjectSet;
}
public IQueryable<T> FindWhere(Expression<Func<T, bool>> predicate)
{
return ObjectSet.Where(predicate);
}
public T FindById(int id)
{
return ObjectSet.Single(i => i.Id == id);
}
public void Add(T newEntity)
{
ObjectSet.AddObject(newEntity);
}
public void Remove(T entity)
{
ObjectSet.DeleteObject(entity);
}
}
Run Code Online (Sandbox Code Playgroud)
通过这种实现,我可以获得大部分功能,如保存,删除,事务处理EF和NH.但是当我开始针对存储库编写复杂的LINQ查询时,大多数时候NH都会失败.当Repository返回NhQueryable时,OrderBy和ToList等一些功能会引发错误.
在下面的代码是从ASP.NET MVC控制器调用的,我正在使用StructureMap注入IUnitOfWork的实例.注入NHibernateUnitOfWork时注入SqlUnitOfWork时,条件未应用于预期的工作位置.
var query = from a in _unitOfWork.AppInfos.FindAll()
join l in _unitOfWork.LogInfos.FindAll()
on a.Id equals l.ApplicationId
where l.Level == "ERROR" || l.Level == "FATAL"
group l by new { a.Id, a.ApplicationName } into g
select new LogInfoSummaryViewModel()
{
ApplicationId = g.Key.Id,
ApplicationName = g.Key.ApplicationName,
ErrorCount = g.Where(i => i.Level == "ERROR").Count(),
FatalCount = g.Where(i => i.Level == "FATAL").Count()
};
return query.AsEnumerable();
Run Code Online (Sandbox Code Playgroud)
Lad*_*nka 14
作为一个没有建立解决方案的一方支持linq之上的不同提供是灾难的方式.Linq和IQueryable漏洞抽象 - 每个Linq提供商都有自己的"功能"和限制.此外,EF本身通过自定义扩展方法IQueryable(在EFv4.1中Include或AsNoTracking在EFv4.1中)添加了一些逻辑.这些方法在内部转换IQueryable为ORM特定的类.
如果你想拥有通用的解决方案,你必须放弃Linq并添加第三个模式来形成抽象.除了Repository和Unit of Work模式之外,您还需要自定义规范模式.通常,您将重新实现NHibernate的Criteria API.
从IoC的角度和对优雅的渴望,你的方式就是你要走的路.然而,我读到的关于NHibernate的linq提供商的所有内容都是它仍然是"beta-ish",因为首先编写Linq提供程序真是太难了.所以很可能你刚刚遇到一个bug.目前我非常不愿意用Linq2Nhibernate编写生产代码.新的QueryOver功能更强大.但是,遗憾的是,QueryOver无法与您的架构无缝融合,因为您必须始终使用NHibernate语法.在您的仓库之外复杂的Linq查询将毫无用处,因为它们永远不会被转换为SQL.
我担心这实际上是你设计优雅的死亡之吻,因为,首先,让一个存储库返回它是没用的IQueryable<T>.但返回IEnumerable<T>会削弱您的EF实施.所以,归结起来,我认为对于查询这两个实现都太不同了,不适合一个简洁的通用接口.
这是QueryOver和Linq上非常有用的帖子.
顺便说一句:这是一个非常有趣的问题和设计.我希望我能投票多一票!
| 归档时间: |
|
| 查看次数: |
3319 次 |
| 最近记录: |