Linq 如何实施与EF和NHibernate合作的工作单元

Linq 如何实施与EF和NHibernate合作的工作单元,linq,nhibernate,entity-framework-4,unit-of-work,Linq,Nhibernate,Entity Framework 4,Unit Of Work,我当时正在开发一个工作单元实现,它在实体框架4.1和NHibernate中都能工作。在下面找到我的实现细节的框架 工作单元定义 public interface IUnitOfWork { IRepository<LogInfo> LogInfos { get; } IRepository<AppInfo> AppInfos { get; } void Commit(); void Rollback(); } public interfa

我当时正在开发一个工作单元实现,它在实体框架4.1和NHibernate中都能工作。在下面找到我的实现细节的框架

工作单元定义

public interface IUnitOfWork
{
    IRepository<LogInfo> LogInfos { get; }
    IRepository<AppInfo> AppInfos { get; }
    void Commit();
    void Rollback();
}
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);
}

从国际奥委会的角度和对优雅的渴望来看,你的方式就是前进的方向。然而,我读到的关于NHibernate的linq提供程序的所有信息是,它仍然是“beta-ish”,因为首先编写linq提供程序非常困难。所以很可能你只是在这里遇到了一个bug。目前,我非常不愿意使用Linq2Nhibernate编写生产代码。新的QueryOver功能更加强大。但是,遗憾的是,QueryOver不能无缝地融入您的体系结构,因为您必须始终使用NHibernate语法。在repo之外的复杂Linq查询将是无用的,因为它们永远不会转换为SQL

恐怕这实际上是对您设计的优雅的致命一击,因为,首先,让存储库返回
IQueryable
是没有用的。但是返回
IEnumerable
将削弱EF实现。所以,归根结底,我认为对于查询,两种实现都太不相同了,不适合一个整洁的通用接口

这是一篇关于QueryOver和Linq的非常有用的文章


顺便说一句:这是一个非常有趣的问题和设计。我希望我能投多一票

作为一个方面,不在linq之上构建支持不同供应的解决方案是灾难之路。Linq和
IQueryable
是有漏洞的抽象-每个Linq提供程序都有自己的“特性”和限制。此外,EF本身通过自定义扩展方法为
IQueryable
(如EFv4.1中的
Include
AsNoTracking
)添加了一些逻辑。这些方法在内部将
IQueryable
转换为ORM特定的类


如果您想要有一个通用的解决方案,您必须放弃Linq并添加第三种模式来形成抽象。除了存储库和工作单元模式之外,您还需要自定义模式。通常,您将重新实现NHibernate的标准API。

除了Ladislav提到的QueryOver的技术困难外,可能还有设计问题。如果您从接口所基于的角度来处理它,并且不公开像
IQueryable
这样纯粹的数据访问概念,那么就不会有这个问题。其中包含您可能会感兴趣的信息和链接。

在抽象数据访问时,这可能也是您感兴趣的
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();
    }
}
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();
    }
}
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);
    }
}
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);
    }
}
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();