数据操作
之前已经学习添加了新API,以及对该API如何进行权限拦截。大多数情况下,我们的API都是要实现数据操作的。那么如何进行数据操作?
要进行数据操作的话,首先要添加实体类,DTO类,配置Dbset, 数据库等一系列工作。
添加实体类,DTO类
实体类,我的理解是这个类的数据是与数据库交流的; DTO类,我的理解是这个类的数据是前后端进行数据交流的。
实体类
实体类在xxx.Core Project添加。我在该Project下建了一个Domain目录,在该目录下添加了一个继承Entity的FileStamp类。代码如下:
using Abp.Domain.Entities;
namespace MyLearningProject.Domain
{
public class FileStamp : Entity<int>
{
public string FileName
{ get; set; }
public string ExtName
{ get; set; }
public string FilePath
{ get; set; }
public int Size
{ get; set; }
public string MD5
{ get; set; }
public string SHA512
{ get; set; }
}
}
DTO类
DTO类在xxxx.Application Project添加。我在该Project下新建一个FileStamp/Dto两层目录,在Dto目录下添加一个继承EntityDto的FileStampDto类。代码如下:
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
namespace MyLearningProject.FileStamp.Dto
{
[AutoMap(typeof(Domain.FileStamp))]
public class FileStampDto:EntityDto<int>
{
public string FileName
{ get; set; }
public string ExtName
{ get; set; }
public string FilePath
{ get; set; }
public int Size
{ get; set; }
public string MD5
{ get; set; }
public string SHA512
{ get; set; }
}
}
重点是,该类需要添加AutoMap 特性,typeof要匹配这个Dto对应的实体类AutoMap(typeof(Domain.FileStamp))
添加DbSet 及 初始化代码
添加DbSet
DbSet在xxxx.EnityFrameworkCore Project添加。该Project下有个EntityFrameworkCore目录,内有xxxDbContext类,在该类内添加相应的DbSet就OK了。代码如下:
using Microsoft.EntityFrameworkCore;
using Abp.Zero.EntityFrameworkCore;
using MyLearningProject.Authorization.Roles;
using MyLearningProject.Authorization.Users;
using MyLearningProject.MultiTenancy;
using MyLearningProject.Domain;
namespace MyLearningProject.EntityFrameworkCore
{
public class MyLearningProjectDbContext : AbpZeroDbContext<Tenant, Role, User, MyLearningProjectDbContext>
{
public MyLearningProjectDbContext(DbContextOptions<MyLearningProjectDbContext> options)
: base(options)
{
}
/* Define a DbSet for each entity of the application */
public DbSet<FileStamp> FileStamp { set; get; }
}
}
数据初始化代码
如果该类需要有初始数据的话,则需要在Seed目录下的SeedHelper内,在其静态方法SeedHostDb内添加相应的代码。例如:
public static void SeedHostDb(MyLearningProjectDbContext context)
{
context.SuppressAutoSetTenantId = true;
// Host seed
new InitialHostDbBuilder(context).Create();
// Default tenant seed (in host database).
new DefaultTenantBuilder(context).Create();
new TenantRoleAndUserBuilder(context, 1).Create();
// 添加数据初始化代码
new DefaultFileStampCreator(context).Create();
}
DefaultFileStampCreator类的代码:
using Microsoft.EntityFrameworkCore;
using MyLearningProject.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyLearningProject.EntityFrameworkCore.Seed.Domain
{
public class DefaultFileStampCreator
{
private readonly MyLearningProjectDbContext _context;
private List<FileStamp> FileInfoList = GetInitialFileInfos();
public DefaultFileStampCreator(MyLearningProjectDbContext context)
{
_context = context;
}
private static List<FileStamp> GetInitialFileInfos()
{
return new List<FileStamp>
{
new FileStamp{FileName="test"},
};
}
public void Create()
{
CreateFileInfos();
}
private void CreateFileInfos()
{
foreach (var info in FileInfoList)
{
AddFileInfoIfNotExists(info);
}
}
private void AddFileInfoIfNotExists(FileStamp info)
{
if (_context.FileStamp.IgnoreQueryFilters().Any(l => l.FileName == info.FileName))
{
return;
}
_context.FileStamp.Add(info);
_context.SaveChanges();
}
}
}
Data Migration
以上准备工作完成后,则需要进行数据库修改工作了
ABP提供了两个命令协助我们很方便的实现Data Migration
-
我们需要进入 程序包管理器控制台界面
-
选择EntityFrameworkCore项目
-
在PM>命令行执行
add-migration "要生成的文件名"
这时系统就会检查相关变更,自动生成#日期#_#要生成的文件名#.cs以及.Designer.cs两个文件
-
在PM>命令行执行
Update-Database
这时系统就会执行新生成的两个文件内的代码,更新数据库
添加API
在xxxx.Application Project添加。刚才在添加Dto时,已经新建了一个FileStamp目录,在该目录下添加一个接口一个类:
using Abp.Application.Services;
namespace MyLearningProject.FileStamp
{
public interface IFileStampAppService : IAsyncCrudAppService<Dto.FileStampDto, int>
{
}
}
using Abp.Domain.Repositories;
namespace MyLearningProject.FileStamp
{
public class FileStampAppService : AsyncCrudAppService<Domain.FileStamp, Dto.FileStampDto, int>, IFileStampAppService
{
public FileStampAppService(IRepository<Domain.FileStamp, int> repository) : base(repository)
{ }
}
}
这样就实现了对FileStamp的CRUD了。
实体类的修改
将FileStamp继承Entity<int>
改为继承AuditedEntity<long>
using Abp.Domain.Entities.Auditing;
namespace MyLearningProject.Domain
{
public class FileStamp : AuditedEntity<long>
{
public string FileName
{ get; set; }
public string ExtName
{ get; set; }
public string FilePath
{ get; set; }
public int Size
{ get; set; }
public string MD5
{ get; set; }
public string SHA512
{ get; set; }
}
}
- 进入 程序包管理器控制台界面
- 选择EntityFrameworkCore项目
- 在PM>命令行执行
add-migration "update-FileStamp"
- 在PM>命令行执行
Update-Database
这时会触发SqlException:
System.Data.SqlClient.SqlException (0x80131904): The object ‘PK_FileStamp’ is dependent on column ‘Id’.
因为刚自动生成的Migration要修改Id的类型,而Id已经作为PK存在,因此,要人手修改代码进行处理。
需要在Up Method一开始添加删除PK,最后完成修改后再添加PK。
而在Down Method结束时加上添加PK.
原自动生成的代码:
public partial class updateFileStamp : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<long>(
name: "Id",
table: "FileStamp",
nullable: false,
oldClrType: typeof(int))
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
.OldAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
......
修改为:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey("PK_FileStamp", "FileStamp"); // 人手添加的
migrationBuilder.AlterColumn<long>(
name: "Id",
table: "FileStamp",
nullable: false,
oldClrType: typeof(int))
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
.OldAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
migrationBuilder.AddColumn<DateTime>(
name: "CreationTime",
table: "FileStamp",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<long>(
name: "CreatorUserId",
table: "FileStamp",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "LastModificationTime",
table: "FileStamp",
nullable: true);
migrationBuilder.AddColumn<long>(
name: "LastModifierUserId",
table: "FileStamp",
nullable: true);
migrationBuilder.AddPrimaryKey("PK_FileStamp", "FileStamp", "Id"); // 人手添加的
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "CreationTime",
table: "FileStamp");
migrationBuilder.DropColumn(
name: "CreatorUserId",
table: "FileStamp");
migrationBuilder.DropColumn(
name: "LastModificationTime",
table: "FileStamp");
migrationBuilder.DropColumn(
name: "LastModifierUserId",
table: "FileStamp");
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "FileStamp",
nullable: false,
oldClrType: typeof(long))
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
.OldAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
migrationBuilder.AddPrimaryKey("PK_FileStamp", "FileStamp", "Id"); // 人手添加的
}
修改完成后,再次执行Update-Database
, 成功执行。
运行程序,测试。一切OK。😘✌️