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提供者。

閱讀其他###

你也可以查看倉儲文檔獲取更多關於倉儲的知識。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM