使用NHibernate的仓储模式?

5
我想知道我的服务层应该了解多少关于存储库的内容?在以前的项目中,我总是返回列表并为所需的每个东西设置一个方法。
例如,如果我需要返回所有ID为5的行,则会有一个方法。我确实拥有用于创建、更新、删除和其他NHibernate选项的通用存储库,但对于查询,我没有。
现在,我开始使用更多的IQueryable,因为我开始遇到为每种情况设置这么多方法的问题。
比如说,如果我需要返回所有具有特定ID且需要3个已加载表格的行,则会有一个新方法。如果我需要某个ID而不需要急切加载,则会有一个单独的方法。
所以现在我在考虑,如果我有一个执行where子句部分并返回IQueryable的方法,那么我就可以添加结果(即如果我需要进行急切加载)。
同时,这使得服务层更加了解存储库层,我不能像现在一样轻松地切换存储库了,因为现在服务层中有特定的NHibernate。
我也不确定这会对模拟造成什么影响。
所以现在我在思考,如果我走这条路,是否还需要存储库,因为它们现在似乎已经混合在一起了。
编辑
如果我摆脱存储库,只在我的服务层中使用会话,那么还需要一个工作单元类吗?
public class UnitOfWork : IUnitOfWork, IDisposable
    {
        private ITransaction transaction;
        private readonly ISession session;

        public UnitOfWork(ISession session)
        {
            this.session = session;
            session.FlushMode = FlushMode.Auto;
        }

        /// <summary>
        /// Starts a transaction with the database. Uses IsolationLevel.ReadCommitted
        /// </summary>
        public void BeginTransaction()
        {
            transaction = session.BeginTransaction(IsolationLevel.ReadCommitted);
        }

        /// <summary>
        /// starts a transaction with the database.
        /// </summary>
        /// <param name="level">IsolationLevel the transaction should run in.</param>
        public void BeginTransaction(IsolationLevel level)
        {
            transaction = session.BeginTransaction(level);
        }

        private bool IsTransactionActive()
        {
            return transaction.IsActive;
        }

        /// <summary>
        /// Commits the transaction and writes to the database.
        /// </summary>
        public void Commit()
        {
            // make sure a transaction was started before we try to commit.
            if (!IsTransactionActive())
            {
                throw new InvalidOperationException("Oops! We don't have an active transaction. Did a rollback occur before this commit was triggered: "
                                                            + transaction.WasRolledBack + " did a commit happen before this commit: " + transaction.WasCommitted);
            }

            transaction.Commit();
        }

        /// <summary>
        /// Rollback any writes to the databases.
        /// </summary>
        public void Rollback()
        {
            if (IsTransactionActive())
            {
                transaction.Rollback();
            }
        }

        public void Dispose() // don't know where to call this to see if it will solve my problem
        {
            if (session.IsOpen)
            {
                session.Close();
            }

        }
2个回答

4

我会更深入地研究它。让我困惑的是,我喜欢服务层不知道数据库的想法,这使得单元测试(如果我需要)和轻松切换ORM变得容易。你如何处理这些情况? - chobo2
我也在想,如果我摆脱了仓库,那么我的工作单元类还有意义吗?请参见编辑。 - chobo2
@chobo2 切换ORM没有简单的方法。如果你使用NHibernate,你想要使用缓存、批量操作、未来查询等功能。这些功能中的一些甚至全部在其他ORM(如EntityFramework)中都不可用。如果你想要抽象化,以便从NH切换到EF,那么你就不能使用那些NH特定的功能。此外,ISession已经是一个抽象层。如果你将复杂的查询放在它们自己的类中,那么你就有了很多抽象层,仍然可以使用NHibernate提供的所有功能。 - Toni Parviainen
@IlyaKogan - 如果所有东西都在同一个类中,使用事务的using语句来包装工作单元会带来什么益处? - chobo2
通常我使用类似TransactionBoundary的东西来处理事务。这假定ISession已经被打开。通过使用using语句,我不必担心可能出现的异常,因为事务会自动回滚。 - Toni Parviainen
显示剩余5条评论

2
NHibernate的一个特点是,如果您不尝试将其抽象出来,它会为您提供最多的帮助。让您的服务层依赖于NHibernate并不一定是一件坏事。这样做可以让您控制会话、缓存和其他NHibernate功能,从而提高性能,更不用说节省了所有您提到的冗余包装代码。

1
补充这个答案:NHibernate Session就是UnitOfWork。 - Ivo
1
这就是为什么我在想,如果我没有使用存储库模式,那么我制作的UnitOfWork类是否有意义? - chobo2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接