ABP MPA

环境说明

  • VS2017
  • SqlServer2014
  • ABP MPA

基础配置

官方模板:

  1. 下载模板
  2. 还原Nuget包
  3. 设置启动项
  4. 修改数据库连接
  5. 数据迁移
  6. 登录系统
    默认账号:admin
    默认密码:123qwe

项目概要

场景:创建人物并分配给用户

实体:

  • 任务Missions
    属性:描述Description、创建时间CreationTime、任务状态State、导航属性AssignedUser
  • 任务用户MissionUsers
    属性:名称Name

领域层创建实体并迁移

Abp.Core

创建实体(Entity)

  1. 创建 Missions 目录并创建 Mission 实体类
$ cd Abp.Core
$ mkdir Missions
$ cd Missions
$ touch Mission.cs
  1. 实体类
  • 实体类继承自EntityEntity类实现了IEntity泛型接口,IEntity通过泛型指定int类型ID主键。
  • 定义创建时间CreationTime通过审计模块中IHasCreationTime实现
  • 定义状态枚举MissionState
  • 定义导航属性AssignedUser用来保存分配任务到某个用户
using Abp.Domain.Entities;
using Abp.Domain.Entities.Auditing;
using Abp.Timing;
using JCP.Authorization.Users;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace JCP.Missions
{
    /**
     * 定义状态枚举
     */
    public enum MissionState:byte
    {
        Disable = 0,
        Enable = 1
    }
    /**
     * 实体类
     * 继承Entity类,Entity类实现IEntity泛型接口。
     * 通过泛型指定主键ID类型,默认Entity主键类型为int类型。
     * 创建时间CreationTime通过审计模块中IHasCreationTime实现
     */
    public class Mission:Entity,IHasCreationTime
    {
        public const int TitleMaxLength = 256;
        public const int DescriptionMaxLength = 1024 * 64;

        public long? UserID { get; set; }
        //导航属性 用来保存分配任务到某个用户
        [ForeignKey("UserID")]
        public User AssignedUser { get; set; }

        [Required]
        [MaxLength(TitleMaxLength)]
        public string Title { get; set; }

        [Required]
        [MaxLength(DescriptionMaxLength)]
        public string Description { get; set; }

        public MissionState State { get; set; }

        public DateTime CreationTime { get; set; }
        //构造器
        public Mission()
        {
            CreationTime = Clock.Now;
            State = MissionState.Enable;
        }
        public Mission(string title, string description=null):this()
        {
            Title = title;
            Description = description;
        }
    }
}

创建数据集(DbSet)

使用EntityFramework需先定义DbContext类,ABP模板已经创建了DbContext文件。

在基础服务层EntityFramework中定义实体对应的DbSet以应用 Code First 数据迁移

$ vim Abp.EntityFramework/EntityFramework/DbContext.cs
//TODO: Define an IDbSet for your Entities...
public IDbSet<JCP.Missions.Mission> Missions { get; set; }

错误

public IDbSet<Mission> Missions { get; set; }
错误  CS0246  未能找到类型或命名空间名“Mission”(是否缺少 using 指令或程序集引用?)

注意:此处要将Core作为EntityFramework的引用
public IDbSet<JCP.Missions.Mission> Missions { get; set; }

执行数据迁移

使用EntityFramework的Code First模式创建数据库架构

ABP模板生成的项目开启数据迁移功能

$ cat EntityFramework/Migrations/Configuration.cs
AutomaticMigrationsEnabled = true;
  • 创建迁移
MP> Add-Migration Add_Mission_Entity

未能加载文件或程序集“Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc”或它的某一个依赖项。
找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

解决方法:在文件中查找(Ctrl+Shift+F)关键字“407dd0808d44fbdc”,保证项目文件配置一致。
<dependentAssembly>
  <assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" culture="neutral" />
  <bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
</dependentAssembly>
The Designer Code for this migration file includes a snapshot of your current Code First model. 
This snapshot is used to calculate the changes to your model when you scaffold the next migration. 
If you make additional changes to your model that you want to include in this migration, 
then you can re-scaffold it by running 'Add-Migration Add_Mission_Entity' again.
namespace JCP.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class Add_Mission_Entity : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Missions",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        UserID = c.Long(),
                        Title = c.String(nullable: false, maxLength: 256),
                        Description = c.String(nullable: false),
                        State = c.Byte(nullable: false),
                        CreationTime = c.DateTime(nullable: false),
                    })
                .PrimaryKey(t => t.Id)
                .ForeignKey("dbo.AbpUsers", t => t.UserID)
                .Index(t => t.UserID);
            
        }
        
        public override void Down()
        {
            DropForeignKey("dbo.Missions", "UserID", "dbo.AbpUsers");
            DropIndex("dbo.Missions", new[] { "UserID" });
            DropTable("dbo.Missions");
        }
    }
}
  • 创建预置种子
$ cd EntityFramework/EntityFramework/Migrations/SeedData/
$ touch DefaultMissionsCreator
using JCP.EntityFramework;
using JCP.Missions;
using System.Collections.Generic;
using System.Linq;

namespace JCP.Migrations.SeedData
{
    class DefaultMissionsCreator
    {
        private readonly JCPDbContext _context;
        private static readonly List<Mission> _missions;

        public DefaultMissionsCreator(JCPDbContext context)
        {
            _context = context;
        }
        static DefaultMissionsCreator()
        {
            _missions = new List<Mission>()
            {
              new Mission("title1", "description1"),
              new Mission("title2", "description2"),
            };
        }

        public void Create()
        {
            foreach(var item in _missions)
            {
                if(_context.Missions.FirstOrDefault(x=>x.Title == item.Title) == null)
                {
                    _context.Missions.Add(item);
                }
                _context.SaveChanges();
            }
        }
    }
}

  • 配置预置种子
$ cd abp.EntityFramework/Migrations/
$ vim Configuration.cs
//Define
new DefaultMissionsCreator(context).Create();
  • 创建数据表
PM> Update-Database
Unable to update database to match the current model because there are pending changes and automatic migration is disabled. 
Either write the pending model changes to a code-based migration or enable automatic migration. 
Set DbMigrationsConfiguration.AutomaticMigrationsEnabled to true to enable automatic migration.
You can use the Add-Migration command to write the pending model changes to a code-based migration.

领域层定义仓储并实现

  • 仓储 Repository 是用来操作数据库进行数据存取
  • 仓储接口在领域层 Core 定义
  • 仓库实现在基础设施层 EntityFramework

ABP中仓储类需实现 IRepository 接口,IRepository 接口定义了常用CURD、聚合操作、同步异步。

ABP针对不同ORM框架对该接口给与了默认实现

  • 针对EF提供了EfRepositoryBase<TDbContext, TEntity, TPrimaryKey>的泛型版本的实现方式
  • 针对NHibernate提供了NhRepositoryBase<TEntity, TPrimaryKey>的泛型版本的实现方式

泛型版本的实现意味着大多数情况下,这些方法已足够应付常规实体的需求。如果方法对于实体来说不够,便需要创建实体所需的接口或类。

仓储的注意事项

  • 仓储的方法中ABP自动进行数据库连接的开启和关闭
  • 仓储方法被调用时,数据库连接自动开启且启动事务。
  • 当仓储方法调用另一个仓储方法时,实际上共享的是同一个数据库连接和事务。
  • 仓储对象是暂时性的,因为IRepository接口默认继承自ITransienetDependency接口。
  • 仓储对象只有在需要时注入,才会由IoC容量自动创建新实例。
  • 默认泛型仓储能满足大部分需求,当无法满足需求时才创建定制化的仓储。

应用服务层使用仓储

通过仓储模式可更好地将业务代码与数据库操作代码更好的分离,可针对不同的数据库有不同的实现类,而业务代码无需修改。

直接通过在应用服务层定义仓储引用,通过构造函数注入即可,ABP提供了一种注入通用仓储的方式。

$ cd Application && mkdir Missions && cd Missions

$ vim IMissionAppService.cs
namespace JCP.Missions
{
    interface IMissionAppService
    {
    }
}

$ vim MissionAppService.cs
using Abp.Domain.Repositories;

namespace JCP.Missions
{
    class MissionAppService:IMissionAppService
    {
        private readonly IRepository<Mission> _missionRepository;
        public MissionAppService(IRepository<Mission> missionRepository)
        {
            _missionRepository = missionRepository;
        }
    }
}

领域层定义仓储接口

需求:

  • 查找用户分配那些任务
  1. 在领域层,创建IRepositories目录,然后定义IBackendMissionRepository
$ cd Core && mkdir IRepositories && cd IRepositories
$ vim IBackendMissionRepository.cs

using Abp.Domain.Repositories;
using JCP.Missions;
using System.Collections.Generic;

namespace JCP.IRepositories
{
    ///<summary>
    ///自定义仓储接口
    ///</summary>
    public interface IBackendMissionRepository:IRepository<Mission>
    {
        /// <summary>
        /// 根据用户编号获取所分配的任务
        /// </summary>
        /// <param name="userid">用户编号</param>
        /// <returns>任务列表</returns>
        List<Mission> GetMissionsByUserID(long userid);
    }
}
  1. 在基础架构层,实现仓储。
  • 仓库的实现继承自模板生成的JCPRepositoryBase泛型抽象类
  • 仓储的实现实现IBackendMissionRepository接口
  • 显式声明实现类的有参构造函数,使用泛型的IDbContextProvider将数据库上下文的子类ChargeStationContext传递给父类的构造方法。
$ vim EntityFramework/EntityRepository/Repositories/BackendMissionRepository.cs

using Abp.EntityFramework;
using JCP.IRepositories;
using JCP.Missions;
using System.Collections.Generic;
using System.Linq;

namespace JCP.EntityFramework.Repositories
{
    class BackendMissionRepository:JCPRepositoryBase<Mission>, IBackendMissionRepository
    {
        public BackendMissionRepository(IDbContextProvider<JCPDbContext> dbContextProvider) : base(dbContextProvider)
        {

        }
        /// <summary>
        /// 根据用户编号获取所分配的任务
        /// </summary>
        /// <param name="userid">用户编号</param>
        /// <returns>任务列表</returns>
        public List<Mission> GetMissionsByUserID(long userid)
        {
            var query = GetAll();
            if(userid > 0)
            {
                query = query.Where(x => x.UserID == userid);
            }
            return query.ToList();
        }
    }
}

基础架构层实现仓储类

在EntityFramework项目中实现定义的IMissionRepository仓储接口

  • 定义基类
$ vim MissionBaseRepository.cs

错误警告

错误

错误  CS0246  未能找到类型或命名空间名“Mission”(是否缺少 using 指令或程序集引用?) 
JCP.EntityFramework 
D:\ASP.NET\VS2017\MPA\JCP.EntityFramework\EntityFramework\JCPDbContext.cs

错误  CS0006  未能找到元数据文件
“D:\ASP.NET\VS2017\MPA\JCP.EntityFramework\bin\Debug\JCP.EntityFramework.dll”

警告

发现“Castle.Core”的不同版本间存在无法解决的冲突。当日志详细信息设置为“详细”时,这些引用冲突将会在生成日志中列出。    

发现同一依赖程序集的不同版本间存在冲突。在 Visual Studio 中,请双击此警告(或选择此警告并按 Enter)以修复冲突;否则,请将以下绑定重定向添加到应用程序配置文件中的“runtime”节点: <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.ValueTuple" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /></dependentAssembly></assemblyBinding>           

发现同一依赖程序集的不同版本间存在冲突。请将项目文件中的“AutoGenerateBindingRedirects”属性设置为 true。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=294190。      

未能找到引用的组件“Microsoft.Owin.Security.Google”   

未能找到引用的组件“Microsoft.Owin.Security.Twitter”。 

“System.ValueTuple, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51”上的显式绑定重定向与自动生成的绑定重定向冲突。请考虑将其从应用程序配置文件中删除或者禁用自动生成的绑定重定向。生成会将其替换为:“<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" xmlns="urn:schemas-microsoft-com:asm.v1" />”。

未能解析此引用。未能找到程序集“Microsoft.Owin.Security.Twitter, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL”。请检查磁盘上是否存在该程序集。 如果您的代码需要此引用,则可能出现编译错误。  JCP.Web         

未能解析此引用。未能找到程序集“Microsoft.Owin.Security.Google, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL”。请检查磁盘上是否存在该程序集。 如果您的代码需要此引用,则可能出现编译错误。   JCP.Web         

Your project specifies TypeScriptToolsVersion 2.2, but a matching compiler was not found. The latest available TypeScript compiler will be used (3.0). To remove this warning, install the TypeScript 2.2 SDK or update the value of TypeScriptToolsVersion.    JCP.Web         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值