实战操作步骤:
一、创建实体
在.Domain项目中创建实体,集合跟,值类型,创建主构造函数确保实体在创建时的有效性, 在代码中通过主构造函数创建实体的新实例。在主构造函数中初始化子级。
示例代码:
//聚合根
public class Issue : FullAuditedAggregateRoot<Guid> //使用Guid作为键/标识符
{
public virtual string Title { get; private set; } //使用 SetTitle() 方法set
public virtual string Text { get; private set; } //可以直接set,null值也是允许的
public virtual Guid? MilestoneId { get; private set; } //引用其他聚合根
public virtual bool IsClosed { get; private set; }
public virtual IssueCloseReason? CloseReason { get; private set; } //一个枚举类型
public virtual Collection<IssueLabel> Labels { get; private set; } //子集合
protected Issue()
{
/* 此构造函数是提供给ORM用来从数据库中获取实体.
* - 无需初始化Labels集合
因为它会被来自数据库的值覆盖.
- It's protected since proxying and deserialization tools
可能不适用于私有构造函数.
*/
}
//主构造函数
public Issue(
Guid id, //从调用代码中获取Guid值
[NotNull] string title, //表示标题不能为空.
string text = null,
Guid? milestoneId = null) //可选参数
{
Id = id;
Title = Check.NotNullOrWhiteSpace(title, nameof(title)); //验证
Text = text;
MilestoneId = milestoneId;
Labels = new Collection<IssueLabel>(); //总是初始化子集合
}
public virtual void SetTitle([NotNull] string title)
{
Title = Check.NotNullOrWhiteSpace(title, nameof(title)); //验证
}
/* AddLabel和RemoveLabel方法管理Labels集合
* 安全的方式(防止两次添加相同的标签) */
public virtual void AddLabel(Guid labelId)
{
if (Labels.Any(l => l.LabelId == labelId))
{
return;
}
Labels.Add(new IssueLabel(Id, labelId));
}
public virtual void RemoveLabel(Guid labelId)
{
Labels.RemoveAll(l => l.LabelId == labelId);
}
/* Close和ReOpen方法可保护一致性
* IsClosed 与 CloseReason 属性. */
public virtual void Close(IssueCloseReason reason)
{
IsClosed = true;
CloseReason = reason;
}
public virtual void ReOpen()
{
IsClosed = false;
CloseReason = null;
}
}
//实体
public class IssueLabel : Entity
{
public virtual Guid IssueId { get; private set; }
public virtual Guid LabelId { get; private set; }
protected IssueLabel()
{
}
public IssueLabel(Guid issueId, Guid labelId)
{
IssueId = issueId;
LabelId = labelId;
}
}
在.Domain.Shared 项目中创建.Domain项目所需要的枚举,常量和其他对象;
如果想要添加初始化数据,需要在.Domain项目的DataSeederContributor.cs文件中添加初始化数据
示例代码:
public class BookStoreDataSeederContributor
: IDataSeedContributor, ITransientDependency
{
private readonly IRepository<Book, Guid> _bookRepository;
public BookStoreDataSeederContributor(IRepository<Book, Guid> bookRepository)
{
_bookRepository = bookRepository;
}
public async Task SeedAsync(DataSeedContext context)
{
if (await _bookRepository.GetCountAsync() <= 0)
{
await _bookRepository.InsertAsync(
new Book
{
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
await _bookRepository.InsertAsync(
new Book
{
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
},
autoSave: true
);
}
}
}
在.Domain.Shared 项目中的文件夹Localization中创建国际化的文件,即页面中显示的语言。每种语音一个json文件,在abp框架中可以根据选择的语音自动调整;
二、创建数据库表
示例使用是的MongoDB数据库,因此在.MongoDB项目的MongoDbContext.cs文件中添加数据库表
示例代码为:
public IMongoCollection<Book> Books => Collection<Book>();
并在MongoDbContextExtensions.cs文件中添加表名前缀
示例代码:
builder.Entity<Book>(b => { b.CollectionName = options.CollectionPrefix + "Book"; });
options.CollectionPrefix为定义的模块名,作为表的前缀
当以上操作完成后设置.DbMigrator 项目为起始项并运行后即可在MongoDB中生成表
三、创建数据传输对象DTO
在.Application.Contracts 项目中创建DTO对象,用于在应用层和表示层或其他类型的客户端之间传输数据。
Entity是不可进行操作的,在外部或前端看到的数据必须使用DTO对象查看。
示例代码:
public class BookDto : AuditedEntityDto<Guid>
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
在此需要进行把.Domain项目中的实体转换为DTO对象,在.Application 项目中的ApplicationAutoMapperProfile.cs文件中添加代码
public class BookStoreApplicationAutoMapperProfile : Profile
{
public BookStoreApplicationAutoMapperProfile()
{
**CreateMap<Book, BookDto>();**
}
}
用此代码自动映射实体Book到对象BookDto。使用了AutoMapper库
四、实现接口
在.Application项目中可以根据传递的参数获取到想要的数据。需要先在在.Application.Contracts 项目中创建传递参数的DTO。
public class CreateUpdateBookDto
{
[Required]
[StringLength(128)]
public string Name { get; set; }
[Required]
public BookType Type { get; set; } = BookType.Undefined;
[Required]
[DataType(DataType.Date)]
public DateTime PublishDate { get; set; } = DateTime.Now;
[Required]
public float Price { get; set; }
}
ABP框架会根据设置自动验证参数规则
还需要创建一个从CreateUpdateBookDto对象到Book实体的映射,最终映射配置类
public BookStoreApplicationAutoMapperProfile()
{
CreateMap<Book, BookDto>();
**CreateMap<CreateUpdateBookDto, Book>();**
}
实体定义好后就需要实现接口了,在.Application.Contracts项目中创建IBookAppService的接口,
public interface IBookAppService :
ICrudAppService< //Defines CRUD methods
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdateBookDto> //Used to create/update a book
{
}
接口定义好后需要实现,在.Application.Contracts项目中创建BookAppService 的类来实现接口
public class BookAppService :
CrudAppService<
Book, //The Book entity
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdateBookDto>, //Used to create/update a book
IBookAppService //implement the IBookAppService
{
public BookAppService(IRepository<Book, Guid> repository)
: base(repository)
{
}
}
在此,API接口已经完成。可以使用Swagger来测试API接口。启动模板配置为使用Swashbuckle.AspNetCore运行swagger UI. 运行应用程序并在浏览器中输入https://localhost:XXXX/swagger/(用自己的端口替换XXXX)作为URL. 使用CTRL+F5运行应用程序 (.HttpApi.Host)并使用浏览器访问https://localhost:/swagger/。 使用自己的端口号替换 。