Посевные данные в EF 2.1 со связанными объектами - PullRequest
0 голосов
/ 02 октября 2018

Использование ASP.NET Core 2.1 и Entity Framework Core 2.1 У меня есть следующие объекты:

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; }
}

Для категорий заполнения у меня есть следующее:

modelBuilder.Entity<Category>().HasData(
  new { Id = 1, Name = "Reading" },
  new { Id = 2, Name = "Travelling" }
);

Однако для заполнениясообщения Я получаю данные из файлов YML:

var posts = _service.GetPostsFromYMLFiles(path);

modelBuilder.Entity<Post>().HasData(posts);

* posts взяты из файлов YML и являются следующими:

new { CategoryName = "Reading", Title = "A", Content = "A Content" },
new { CategoryName = "Travelling", Title = "B", Content = "B Content" }

Эти файлы YML создаются третьейparty, и я не могу их изменить.

Чтобы заполнить эти посты, я считаю, что мне нужно:

  1. Получить соответствующий идентификатор категории для каждого CategoryName;
  2. Создать идентификатордля каждого сообщения.

Шаг (2) кажется простым, но как мне выполнить шаг (1)?

Ответы [ 2 ]

0 голосов
/ 02 октября 2018

Вместо заполнения категорий на месте, сначала сохраните их в переменную:

var categories = new[] 
{
    new Category { Id = 1, Name = "Reading" },
    new Category { Id = 2, Name = "Traveling" }
};

Затем передайте это HasData:

modelBuilder.Entity<Category>().HasData(categories);

С этим вы можетеТеперь запросите этот список в памяти, чтобы получить соответствующие категории при сопоставлении ваших данных YML с вашими Post сущностями:

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 не обнуляется, так что вы, вероятно, захотите создать запасной вариант для ifконкретная категория, названная в вашем YML, на самом деле не существует.Вы можете даже подумать о выделении самих категорий из поста YML, чтобы убедиться, что там действительно есть все:

var categories = posts.Select(p => p.CategoryName).Distinct().Select((c, i) => new Category
{
    Id = i,
    Name = c
}).ToArray();
0 голосов
/ 02 октября 2018

Чтобы заполнить эти посты, я считаю, что мне нужно:

Получить соответствующий идентификатор категории для каждого CategoryName;

Создать идентификатор для каждого сообщения.

Да!Ты прав!Вы должны использовать CategoryId вместо CategoryName в Post, потому что CategoryId - это ключ реляции, а не CategoryName.Таким образом, ваш контент YML должен выглядеть следующим образом:

new {Id = 1, CategoryId = 1, Title = "A", Content = "A Content" },
new {Id = 2, CategoryId = 2, Title = "B", Content = "B Content" }

Затем в OnModelCreating из DbConext следующим образом:

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);        
}

Эти файлы YML созданытретьей стороной, и я не могу их изменить.

Затем вы должны написать собственный метод обслуживания, где вы будете проверять каждое сообщение в файле YMl с помощью CategoryName, затем вы должны составить новый список Post, где вы замените CategoryName на CateogryId и его соответствующее значение следующим образом:

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;
    }
}

Затем в OnModelCreating из DbConext следующим образом:

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);

}
...