zoukankan      html  css  js  c++  java
  • ABP理论学习之NHibernate集成

    返回总目录


    本篇目录

    ABP可以使用任何ORM框架工作,并且已经内置了NHibernate集成。这篇文章会解释如何在ABP中使用NHibernate。阅读本文的前提是假设你已经熟悉了EF的基本知识。

    Nuget包###

    在ABP中使用NH作为ORM的Nuget包是Abp.NHibernate。你应该将它添加到应用程序中。最好在应用程序中分离的程序集(dll)中实现NHibernate,并让该程序集依赖Abp.NHibernate包。

    配置###

    要开始使用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());
        }
    }
    
    

    AbpNHibernate模块为了使ABP能够使用NHibernate工作提供了基本的功能和适配器。

    实体映射

    在下面的样例配置中,使用了当前程序集中的所有映射类进行了流畅地映射。一个映射类的例子如下所示:

    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的一个类,它会自动映射 Id属性并在构造函数中获得表名。因此,我们可以从它派生并使用 FluentNHibernate映射其他的属性。当然,你可以直接从ClassMap派生,可以使用FluentNHibernate的所有API,也可以使用NHinernate其他的映射技术(比如映射XML文件)。

    仓储###

    你可以使用仓储的默认实现而不用在项目中创建仓储类。或者可以创建派生自NhRepositoryBase的仓储类。

    仓储基类

    虽然可以从ABP的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)
        {
        }
    
        //不要在这里添加任何方法,在上面的方法中添加(因为该方法继承了上面的方法)
    }
    
    public class TaskRepository : MyRepositoryBase<Task>, ITaskRepository
    {
        public TaskRepository(ISessionProvider sessionProvider)
            : base(sessionProvider)
        {
        }
    
        //这里添加一些task仓储特有的方法
    }
    
    

    默认实现

    你不需要为实体类创建仓储,只需要使用预定义的仓储方法。例子:

    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并使用仓储中的Insert方法。使用这种方法,你可以轻松地注入 IRepository(或者IRepository<TEntity,TPrimaryKey>),然后使用预定义的方法。所有预定义的方法列表,请查看仓储文档

    自定义仓储方法

    如果你想添加一些自定义的方法,那么首先应该给它添加仓储接口(这是最佳实践),然后在仓储类中实现。ABP提供了一个基类NhRepositoryBase来轻松地实现仓储。要实现仓储接口,只需要从仓储基类中派生仓储就可以了。

    假设我们有一个Task(任务)实体,该任务可以派给一个Person(人)实体,而且Task实体有这么几种状态,包括new,assigned,completed等等。我们可能需要写一个自定义方法来根据一些条件和AssignedPerson来获取任务的列表。看下面的代码:

    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,然后使用给定的参数添加了一些 Where过滤。最后使用 ToList()获得Tasks的列表。

    你也可以在仓储方法中使用Session对象来调用NHibernate的全部API。

    仓储应该在它的构造函数中获得一个ISessionProvider。这样的话,我们就可以在单元测试中轻松地注入一个伪造的session提供者了。在运行时,ABP会自动地注入正确的session提供者。

    阅读其他###

    你也可以查看仓储文档获取更多关于仓储的知识。

  • 相关阅读:
    Token ,Cookie和Session的区别
    极致Web性能 —— SPA性能指南
    关于前端数据&逻辑的思考
    移动端Retina屏boder 1px显示为2px或3px的解决方法
    Java连载8-基本数据类型2
    HTML连载25-通配符选择器&选择器综合练习
    Python连载25-函数tell&write&writeline$&持久化
    Python连载24-函数list&read&seek
    Java连载7-变量&数据类型
    HTML连载24-属性选择器(下)
  • 原文地址:https://www.cnblogs.com/farb/p/ABPNHibernate.html
Copyright © 2011-2022 走看看