Using ASP.NET Core 2.1 and Entity Framework Core 2.1 I have the following entities:
public class Category {
public Int32 Id { get; set; }
public String Name { get; set; }
}
public class Post {
public Int32 Id { get; set; }
public Int32 CategoryId { get; set; }
public String Title { get; set; }
public String Content { get; set; }
public virtual Category Category { get; set; }
}
For seeding Categories I have the following:
modelBuilder.Entity<Category>().HasData(
new { Id = 1, Name = "Reading" },
new { Id = 2, Name = "Travelling" }
);
However, for seeding posts I am getting the data from YML files:
var posts = _service.GetPostsFromYMLFiles(path);
modelBuilder.Entity<Post>().HasData(posts);
The posts
are taken from YML files and are the following:
new { CategoryName = "Reading", Title = "A", Content = "A Content" },
new { CategoryName = "Travelling", Title = "B", Content = "B Content" }
These YML files are created by a third party and I cannot change them.
To seed these posts I believe I need to:
The step (2) seems easy but how can I accomplish step (1)?
Instead of seeding the categories in place, save them to a variable first:
var categories = new[]
{
new Category { Id = 1, Name = "Reading" },
new Category { Id = 2, Name = "Traveling" }
};
Then, pass this to HasData
:
modelBuilder.Entity<Category>().HasData(categories);
With that, you can now query this list in memory to get the relevant categories while mapping your YML data to your Post
entities:
var posts = _service.GetPostsFromYMLFiles(path);
modelBuilder.Entity<Post>().HasData(posts.Select((p, i) => new Post
{
Id = i,
Title = p.Title,
Content = p.Content,
CategoryId = categories.Single(c => c.Name == p.CategoryName).Id
});
CategoryId
is non-nullable, so you probably want to create a fallback for if a particular category named in your YML does not actually exist. You may even consider seeding the categories themselves from the post YML, to ensure that everything in there actually exists:
var categories = posts.Select(p => p.CategoryName).Distinct().Select((c, i) => new Category
{
Id = i,
Name = c
}).ToArray();
To seed these posts I believe I need to:
Get the correspondent Category Id for each CategoryName;
Generate an ID for each post.
Yes! You are correct! you have to use CategoryId
instead of CategoryName
in the Post
because CategoryId
is the relational Key, not CategoryName
. So your YML content should be like as follows:
new {Id = 1, CategoryId = 1, Title = "A", Content = "A Content" },
new {Id = 2, CategoryId = 2, Title = "B", Content = "B Content" }
Then in the OnModelCreating
of the DbConext
as follows:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var posts = _service.GetPostsFromYMLFiles(path);
modelBuilder.Entity<Category>().HasData(
new { Id = 1, Name = "Reading"},
new { Id = 2, Name = "Travelling" }
);
modelBuilder.Entity<Post>().HasData(posts);
}
These YML files are created by a third party and I cannot change them.
Then you have to write a custom service method where you will check every post in YMl file with CategoryName
then you have to make new list of Post
where you will replace CategoryName
with CateogryId
and its appropriate value as follows:
public class YmlPost
{
public string CategoryName { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
public class SeedDataService
{
static List<Category> categoryList = new List<Category>()
{
new Category { Id = 1, Name = "Reading" },
new Category { Id = 2, Name = "Traveling" }
};
public static List<Category> GetCategoriesForSeeding()
{
return categoryList;
}
public static List<Post> GetPostsForSeeding()
{
List<YmlPost> postListFromYML = _service.GetPostsFromYMLFiles(path);
List<Post> posts = postListFromYML.Select((p, i) => new Post
{
Id = i+1, // index is 0 based that's why you have to add 1.
Title = p.Title,
Content = p.Content,
CategoryId = categoryList.Single(c => c.Name ==
p.CategoryName).Id
}).ToList();
return posts;
}
}
Then in the OnModelCreating
of the DbConext
as follows:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var categories = SeedDataService.GetCategoriesForSeeding();
modelBuilder.Entity<Category>().HasData(categories);
var posts = SeedDataService.GetPostsForSeeding();
modelBuilder.Entity<Post>().HasData(posts);
}