【问题标题】:Using Fluent NHibernate with a Data Access Layer将 Fluent NHibernate 与数据访问层一起使用
【发布时间】:2013-10-10 22:43:08
【问题描述】:

首先介绍一下背景:我有一个包含以下 3 个项目的解决方案:

  • MVC 项目(面向用户的网站)
  • API 项目(业务逻辑项目)
  • 数据访问项目(NHibernate 所在的项目)

我在 DA 层中有 Fluent 映射,并且(目前)我在 MVC 站点的 GLobal.asax 中构建了 Hibernate SessionFactory。这并不理想,因为我希望 NHibernate 完全包含在 DA 层中,并且 MVC 应用程序只与 API 层通信。另外,我只想构建一次SessionFactory,因为这是一项昂贵的操作。

为了让事情更复杂,我有一个这样的继承结构:

  • API 层中的User object 继承自
  • DA 层中的User data object 继承自
  • Data object 在 DA 层。

Data object 负责将对象保存到数据库,因为保存功能在所有对象中都是相同的,我不想重复代码。我遇到的问题是如何将User objectData object 类内部保存到数据库中,同时使用我在用户登录网站时实例化的SessionFactory,并且可以在他们的会话中持续存在。

如果有什么没有解释清楚,请告诉我。

【问题讨论】:

    标签: c# asp.net-mvc nhibernate design-patterns fluent-nhibernate


    【解决方案1】:

    一种方法是使用DI pattern,例如团结。

    实现你的data object 有一个构造函数,例如一个IRepository 接口。此接口的实现处理 nHibernate 会话工厂...

    您的data object 也可以是通用的,其中T 是其中之一,例如User data object。然后你在data object 中实现一个方法,例如使用注入的IRepository保存、更新、删除T

    data object 的伪代码

    public interface IEntity
    {
    }
    
    public interface IRepository
    {
        ISession Session { get; }
    }
    
    public class DataObjectBase<T> where T : IEntity
    {
        private IRepository Repository { get; set; }
    
        public DataObjectBase(IRepository repository)
        {
            this.Repository = repository;
        }
    
        public T Get(int id)
        {
            return Repository.Session.Get<T>(id);
        }
    
        public void Save(T value)
        {
            Repository.Session.Save(value);
        }
    
        public void Update(T value)
        {
            Repository.Session.Update(value);
        }
    
        public void Delete(T value)
        {
            Repository.Session.Delete(value);
        }
    
        public IQueryable<T> Query()
        {
            return Repository.Session.Query<T>();
        }
    }
    

    具体数据对象的实现

    public class ADataObject : IEntity
    {
        public int Id { get; set; }
    
        // [...]
    }
    

    为数据对象实现数据上下文

    public class ADataObjectContext : DataObjectBase<ADataObject>
    {
        public ADataObjectContext(IRepository repository)
            : base(repository)
        {
        }
    }
    

    使用 Unity 的简单示例测试

    public class Test
    {
        public void Run()
        {
            IUnityContainer myContainer = new UnityContainer();
            myContainer.RegisterType<IRepository, NHibernateRepository>();
    
            var ctx = myContainer.Resolve<ADataObjectContext>();
    
            var obj = ctx.Query().Where(p => p.Id == 2);
        }
    }
    

    当然,您必须实现 NHibernateRespository 才能做任何您想做的事情。

    UnityContainer 初始化应该在 MVC 项目中的 global.asax 中完成。您还可以通过 web.config 配置 Unity。

    NHibernateRespository 实际上应该是一个单例。这可以由您实现,或者您只需使用 Unity 功能将您的类型实例化为单例。 new ContainerControlledLifetimeManager() 正是这样做的。

    除了将会话公开为属性之外,您还可以公开一个打开新会话的方法。或者您实现一个开始和结束工作单元,这是 Web 环境中的常见做法......

    普通存储库模式、工作单元、统一性的其他链接...或者只是在 Google 上搜索 nhibernate 存储库模式

    http://slynetblog.blogspot.de/2011/11/in-spite-of-common-now-approach-of.html

    http://blog.bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/

    http://msdn.microsoft.com/en-us/library/dd203101.aspx

    【讨论】:

    • 感谢您的详细解答。我不熟悉 DI 的实现,所以我希望我可以在没有 DI 的情况下做到这一点,但我想这给了我一个学习的借口。
    【解决方案2】:

    您可以使用以下选项:

    • 使用 AOP:当 API 层调用函数时,AOP 会创建一个会话,并将方法或构造函数中的值参数传递给 DA 层。
    • 从 MVC 项目到 DA 层,它通过所有层将会话通过方法或构造函数中的参数传递到 DA 层。

    认为会话总是与接口层相关联。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-27
      • 2011-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多