• ABP 基础设施层——集成 NHibernate


        本文翻译自ABP的官方教程《NHibernate Integration》,地址为:http://aspnetboilerplate.com/Pages/Documents/NHibernate-Integration

        ABP可以与任何ORM框架协同工作,它内置了对NHibernate的集成支持。本文将介绍如何在ABP中使用NHibernate。本文假定你已经初步掌握了NHibernate。

        译者注:怎么才算初步掌握了NHibernate呢?译者认为应当懂得使用NHibernate进行CRUD,懂得使用Fluent模式进行映射。

    1 Nuget包

        要在ABP中使用NHibernate作为ORM框架的话,需要到Nuget上下载一个名为Abp. NHibernate 的包。比较好的做法是:新建一个独立的程序集(dll),然后在这个程序集中调用这个包和NHibernate。

    2 配置(Configuration)

        要使用Nhibernate,首先要对它进行配置,配置的方法是在模块的PreInitialize方法中编写配置代码,如下所示:

     [DependsOn(typeof(AbpNHibernateModule))]
     public class SimpleTaskSystemDataModule : AbpModule
     {
         public override void PreInitialize()
         {
             var connStr = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
             Configuration.Modules.AbpNHibernate().FluentConfiguration
                 .Database(MsSqlConfiguration.MsSql2008.ConnectionString(connStr))
                 .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()));
         }
       public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
        }
    }

        ABP之所以能与Nhibernate协同工作,是因为内置的AbpNHibernateModule模块提供了必要的适配器。

        (1)实体映射(Entity mapping

        在下面的示例中,我们使用Fluent映射模式来对所有的实体类进行映射:

    public class TaskMap : EntityMap<Task>
    {
        public TaskMap()
            : base("TeTasks")
        {
            References(x => x.AssignedUser).Column("AssignedUserId").LazyLoad();
            Map(x => x.Title).Not.Nullable();
            Map(x => x.Description).Nullable();
            Map(x => x.Priority).CustomType<TaskPriority>().Not.Nullable();
            Map(x => x.Privacy).CustomType<TaskPrivacy>().Not.Nullable();
            Map(x => x.State).CustomType<TaskState>().Not.Nullable();
        }
    }

        EntityMap类是ABP中的一个内置类,它派生自ClassMap<T>类,可以自动地对Id属性进行映射,并且在构造函数中获取表名。在上例中我们从EntityMap中派生,然后使用FluentNHibernate来映射其它属性。当然,你也可以直接从ClassMap中派生。在ABP中,你可以使用FluentNHibernate中定义的所有API。

        在上例中我们使用了Fluent映射模式,你也可以使用其它映射模式,比如基于xml文件的映射模式。

        译者注:Nhibernate有四种映射模式:(1)基于XML的映射。(2)基于特性的映射。(3)Fluent映射。(4)基于约定的映射,也称为自动映射。

    3 仓储实现(Repository implementation)

        如果需求比较简单的话,你甚至不需要创建单独的仓储类,直接使用仓储的默认实现即可。如果实在需要创建单独的仓储类的话,建议从NhRepositoryBase中派生。

        (1默认实现(Default implementation)

        如果你只想使用预定义的仓储方法的话,你甚至不需要为实体创建单独的仓储类。如下所示:

    public class PersonAppService : IPersonAppService
    {
        private readonly IRepository<Person> _personRepository;
        public PersonAppService(IRepository<Person> personRepository)
        {
            _personRepository = personRepository;
        }
    
        public void CreatePerson(CreatePersonInput input)
        {       
            person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };
            _personRepository.Insert(person);
        }
    }

        PersonAppService类采用构造函数注入的方式注入了一个IRepository<Person>对象,然后调用了预定义的Insert方法。采用这种方式,你可以方便地注入IRepository<TEntity> (或者IRepository<TEntity, TPrimaryKey>)对象,然后调用预定义的方法。请查看仓储文档以获得预定义方法的列表。

       (2)自定义仓储(Custom repositories

        如果你想添加自定义方法,最佳的作法是,首先将它添加到仓储接口中,然后在仓储类中实现。ABP提供了一个名为NhRepositoryBase的基类,这使得实现仓储变得简单快捷,要实现IRepository接口,只需要从这个基类中派生。

        假定我们有一个名为Task的实体,它可以被赋予Person实体。Task有一个State属性(值为新建、已分配、已完成等)。我们需要编写一个自定义方法,这个方法能根据某些条件获取Task列表,并且使得Task的AssisgnedPerson属性可以在一次数据库查询中被加载(使用NHibernate的立即加载方法Fetch)。如下所示:

    public interface ITaskRepository : IRepository<Task, long>
    {
        List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state);
    }
    
     
    
    public class TaskRepository : NhRepositoryBase<Task, long>, ITaskRepository
    {
        public TaskRepository(ISessionProvider sessionProvider)
            : base(sessionProvider)
        {
    
        }
    
     
        public List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state)
        {
            var query = GetAll();
            if (assignedPersonId.HasValue)
            {
                query = query.Where(task => task.AssignedPerson.Id == assignedPersonId.Value);
            }
    
            if (state.HasValue)
            {
                  query = query.Where(task => task.State == state);
            }
    
    
            return query
                .OrderByDescending(task => task.CreationTime)
                .Fetch(task => task.AssignedPerson)
                .ToList();
        }
    }

        预定义方法GetAll()返回了一个IQueryable<Task>对象,接着我们将参数放入到Where筛选器中,最后调用ToList()来获得一个Task列表。

    此外,你可以通过调用base.Session属性来获得一个Session对象,这样一来,你就可以直接使用NHibernate的所有功能。

    仓储类应当在构造函数中获取ISessionProvider对象。通过这种方式,在单元测试的时候,我们可以很容易地注入一个虚拟的 Session Provider 对象;而在运行的时候, ABP 会根据配置注入相应的 Session Provider对象。

        (3)应用程序专用的仓储基类(Application specific base repository class

        要实现仓储类,只需要从NhRepositoryBase中派生即可。但是更好的做法是,自定义一个派生自NhRepositoryBase的基类,然后在这个基类中添加一些通用的方法。这样做的好处是,所有派生自这个基类的仓储都继承了这些通用方法。

    // 应用程序中的所有仓储的基类
    
    public abstract class MyRepositoryBase<TEntity, TPrimaryKey> : NhRepositoryBase<TEntity, TPrimaryKey>
        where TEntity : class, IEntity<TPrimaryKey>
    {
        protected MyRepositoryBase(ISessionProvider sessionProvider)
            : base(sessionProvider)
        {
    
        }
    
        // 添加仓储基类的通用方法
    }
    
    
    //为所有拥有整型 Id 的实体添加一个快捷方式
    
    
    public abstract class MyRepositoryBase<TEntity> : MyRepositoryBase<TEntity, int>
        where TEntity : class, IEntity<int>
    {
        protected MyRepositoryBase(ISessionProvider sessionProvider)
            : base(sessionProvider)
        {
    
        }
    
    
    // 不 要 在 这 里 添 加 任 何 通 用 方 法 ,通 用 方 法 应 当 被添加到 上 面 的 基 类 中(MyRepositoryBase<TEntity, TPrimaryKey>)
    }
    
    
    
    public class TaskRepository : MyRepositoryBase<Task>, ITaskRepository
    {
        public TaskRepository(ISessionProvider sessionProvider)
            : base(sessionProvider)
        {
    
        }
    
    
        // 添加本仓储类的专用方法
    
    
    }
  • 相关阅读:
    boltdb 学习和实践
    解读-m addrtype --dst-type LOCAL -j DOCKER
    找到linux中当前java的安装位置
    java.library.path是什么?
    Linux 中【./】和【/】和【.】之间有什么区别?
    [SpringMVC]JSON乱码问题
    iOS MVVM的理解与分析
    iOS中为什么必须在主线程操作UI
    几种直播流媒体协议
    IOS硬编码
  • 原文地址:https://www.cnblogs.com/dehai/p/4713489.html
Copyright © 2020-2023  润新知