ABP VNext种子数据按顺序插入
1.Domain层
1.1 新加Author和Book实体
public class Author : FullAuditedAggregateRoot<Guid>
{
public string Name { get; private set; }
public DateTime BirthDate { get; set; }
public string ShortBio { get; set; }
private Author()
{
/* This constructor is for deserialization / ORM purpose */
}
internal Author(
Guid id,
[NotNull] string name,
DateTime birthDate,
[CanBeNull] string shortBio = null)
: base(id)
{
SetName(name);
BirthDate = birthDate;
ShortBio = shortBio;
}
internal Author ChangeName([NotNull] string name)
{
SetName(name);
return this;
}
private void SetName([NotNull] string name)
{
Name = Check.NotNullOrWhiteSpace(
name,
nameof(name),
maxLength: 100
);
}
}
public class Book : AuditedAggregateRoot<Guid>, IMultiTenant
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
public Guid AuthorId { get; set; }
public Guid? TenantId { get; set; }
}
1.2 CustomDataSeedDbMigrationService新加方法
CustomDataSeedDbMigrationService中的MigrateAsync方法中添加自定义的种子数据插入方法:
private async Task CustomSeedDataAsync(bool isUseCustomRank = true)
{
var dataSeedContext = new DataSeedContext()
.WithProperty(IdentityDataSeedContributor.AdminEmailPropertyName, "admin@ycims.com")
.WithProperty(IdentityDataSeedContributor.AdminPasswordPropertyName, "ycqwe123")
.WithProperty("IsUseCustomRank", isUseCustomRank);
await _dataSeeder.SeedAsync(dataSeedContext);
}
MigrateAsync完整代码:
public async Task MigrateAsync()
{
var initialMigrationAdded = AddInitialMigrationIfNotExist();
if (initialMigrationAdded)
{
return;
}
Logger.LogInformation("Started database migrations...");
await MigrateDatabaseSchemaAsync();
await SeedDataAsync();
//自定义顺序插入种子数据
await CustomSeedDataAsync();
Logger.LogInformation($"Successfully completed host database migrations.");
var tenants = await _tenantRepository.GetListAsync(includeDetails: true);
var migratedDatabaseSchemas = new HashSet<string>();
foreach (var tenant in tenants)
{
using (_currentTenant.Change(tenant.Id))
{
if (tenant.ConnectionStrings.Any())
{
var tenantConnectionStrings = tenant.ConnectionStrings
.Select(x => x.Value)
.ToList();
if (!migratedDatabaseSchemas.IsSupersetOf(tenantConnectionStrings))
{
await MigrateDatabaseSchemaAsync(tenant);
migratedDatabaseSchemas.AddIfNotContains(tenantConnectionStrings);
}
}
await SeedDataAsync(tenant);
}
Logger.LogInformation($"Successfully completed {tenant.Name} tenant database migrations.");
}
Logger.LogInformation("Successfully completed all database migrations.");
Logger.LogInformation("You can safely end this process...");
}
1.3新加ISowSeed接口
public interface ISowSeed
{
/// <summary>
/// 种子执行顺序(从小到大执行)
/// </summary>
int Sort { get; set; }
Task ExecAsync(DataSeedContext context);
}
1.4 作者和图书种子数据逻辑
这里作者的数据顺序为1,图书为2
public class AuthorSowSeed : ISowSeed, ITransientDependency
{
private readonly IRepository<Author, Guid> _authorRepository;
private readonly IGuidGenerator _guidGenerator;
public AuthorSowSeed(IRepository<Author, Guid> authorRepository, IGuidGenerator guidGenerator)
{
_authorRepository = authorRepository;
_guidGenerator = guidGenerator;
}
public int Sort { get; set; } = 1;
public async Task ExecAsync(DataSeedContext context)
{
await this.MockData();
}
private async ValueTask MockData()
{
var author1 = await _authorRepository.FindAsync(s => s.Name == "George Orwell");
if (author1 == null)
{
await _authorRepository.InsertAsync(new Author(_guidGenerator.Create(), "George Orwell", new DateTime(1903, 06, 25), "Orwell produced literary criticism and poetry, fiction and polemical journalism; and is best known for the allegorical novella Animal Farm (1945) and the dystopian novel Nineteen Eighty-Four (1949)."), autoSave: true);
}
var author2 = await _authorRepository.FindAsync(s => s.Name == "Douglas Adams");
if (author2 == null)
{
var douglas = await _authorRepository.InsertAsync(new Author(_guidGenerator.Create(), "Douglas Adams", new DateTime(1952, 03, 11), "Douglas Adams was an English author, screenwriter, essayist, humorist, satirist and dramatist. Adams was an advocate for environmentalism and conservation, a lover of fast cars, technological innovation and the Apple Macintosh, and a self-proclaimed 'radical atheist'."), autoSave: true);
}
}
}
public class BookSowSeed : ISowSeed, ITransientDependency
{
private readonly IRepository<Book, Guid> _bookRepository;
private readonly IRepository<Author, Guid> _authorRepository;
public BookSowSeed(IRepository<Book, Guid> bookRepository, IRepository<Author, Guid> authorRepository)
{
_bookRepository = bookRepository;
_authorRepository = authorRepository;
}
public int Sort { get; set; } = 2;
public async Task ExecAsync(DataSeedContext context)
{
await this.MockData();
}
private async ValueTask MockData()
{
var book1 = await _bookRepository.FindAsync(s => s.Name == "1984");
if (book1 == null)
{
await _bookRepository.InsertAsync(
new Book
{
AuthorId = (await _authorRepository.FindAsync(s => s.Name == "George Orwell")).Id, // SET THE AUTHOR
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
}
var book2 = await _bookRepository.FindAsync(s => s.Name == "The Hitchhiker's Guide to the Galaxy");
if (book2 == null)
{
await _bookRepository.InsertAsync(
new Book
{
AuthorId = (await _authorRepository.FindAsync(s => s.Name == "Douglas Adams")).Id, // SET THE AUTHOR
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
},
autoSave: true
);
}
}
}
1.5 新加CustomDataSeedDataSeederContributor
internal class CustomDataSeedDataSeederContributor : IDataSeedContributor, ITransientDependency
{
private readonly IEnumerable<ISowSeed> _dataSowSeeds;
public CustomDataSeedDataSeederContributor(IEnumerable<ISowSeed> dataSowSeeds)
{
this._dataSowSeeds = dataSowSeeds;
}
public async Task SeedAsync(DataSeedContext context)
{
if (!context.Properties.ContainsKey("IsUseCustomRank"))
{
return;
}
var items = _dataSowSeeds.OrderBy(p => p.Sort);
foreach (var item in items)
{
await item.ExecAsync(context);
}
}
}
2.EntityFrameworkCore
2.1 CustomDataSeedDbContext
public DbSet<Book> Books { get; set; }
public DbSet<Author> Authors { get; set; }
builder.Entity<Book>(b =>
{
b.ToTable(CustomDataSeedConsts.DbTablePrefix + "Books",
CustomDataSeedConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
b.HasOne<Author>().WithMany().HasForeignKey(x => x.AuthorId).IsRequired();
});
builder.Entity<Author>(b =>
{
b.ToTable(CustomDataSeedConsts.DbTablePrefix + "Authors",
CustomDataSeedConsts.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.Name)
.IsRequired()
.HasMaxLength(100);
b.HasIndex(x => x.Name);
});
2.2 生成迁移脚本
dotnet ef migrations add AddBooks
2.3 应用到数据库
应用到数据库之后,启动CustomDataSeed.DbMigrator项目可以打断点查看种子数据生成顺序
dotnet ef database update