数据库播种仅适用于一种模型,不适用于另一种模型

时间:2019-07-06 11:38:26

标签: c# asp.net asp.net-mvc asp.net-core

我正在将测试数据植入两个模型AuthorPost中。播种适用于Author,但似乎无声地失败了Post

编辑:我想我已经找到了问题的根源。我发现了异常,消息是

  

Post设置为OFF时,无法为表IDENTITY_INSERT中的标识列插入显式值。

this StackOverflow post中可能有解决此问题的方法,但是我想知道是否有人对此有何想法?这是因为我们不应该手动设置主键的值吗?

我没有遵循this Microsoft Docs tutorial,但是使用的是ASP.NET MVC Core 2.1。基本策略是Main()类中的Program方法调用DbInitializer.Initialize(),如果上下文中没有Authors,它将为数据提供种子。

我已经跨过DbInitializer类,两个模型的代码都经过相同的过程,遍历种子数组,将其添加到上下文中并(显然)保存更改。但是,虽然Author数据库字段填充有种子数据,但Post字段却未填充。

编辑:在逐步检查生成的上下文时,有时Author字段具有奇怪的ID值,有时Post字段具有奇怪的ID值:-2147492647 ,-2147492646等...我试图将导致问题的机会从PostID更改为ID,但是该字段名称也发生了同样的问题。

我的第二个想法是想知道这是否与Post和Author之间的多对一关系有关。但是,我尝试仅使用Post字段来播种Title数据(因此不包括外键AuthorID),但这没有什么区别。我是ASP.NET的新手,所以我希望我缺少明显的东西。感谢您的指导。

MyWebsiteContext.cs

using Microsoft.EntityFrameworkCore;
using MyWebsite.Models;

namespace MyWebsite.Models
{
    public class MyWebsiteContext : DbContext
    {
        public MyWebsiteContext (DbContextOptions<MyWebsiteContext> options)
            : base(options)
        {
        }
        public DbSet<MyWebsite.Models.Author> Author { get; set; }

        public DbSet<MyWebsite.Models.Post> Post { get; set; }
    }
}

DbInitializer.cs

using MyWebsite.Models;

namespace MyWebsite.Data
{
    public class DbInitializer
    {
        public static void Initialize(MyWebsiteContext context)
        {
            // Look for any authors; if none, seed DB.
            if (context.Author.Any())
            {
                return; // DB has already been seeded.
            }

            var authors = new Author[]
            {
                new Author{ FirstName="Terry",LastName="Pratchett",SignUpDate=DateTime.Parse("2019-04-01")},
                new Author{ FirstName="Neil",LastName="Gaiman",SignUpDate=DateTime.Parse("2019-03-02")},
            };

            foreach (Author a in authors)
            {
                context.Author.Add(a);
            }
            context.SaveChanges();

            var posts = new Post[]
            {
                new Post{PostID=1,Title="Title of post 1"},
                new Post{PostID=2,Title="Title of post 2"},
                new Post{PostID=3,Title="Title of post 3"},
            };
            foreach (Post p in posts)
            {
                context.Post.Add(p);
            }
            context.SaveChanges();
        }
    }
}

Program.cs

using System;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MyWebsite.Data;
using MyWebsite.Models;

namespace MyWebsite
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    var context = services.GetRequiredService<MyWebsiteContext>();
                    DbInitializer.Initialize(context);
                }
                catch(Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }
            host.Run();
        }
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

Post.cs

namespace MyWebsite.Models
{
    public class Post   // Post entity is dependent on Author class
    {
        public int PostID { get; set; } // primary key
        public string Title { get; set; }
        public int AuthorID { get; set; } // foreign key
        public Author Author { get; set; }
    }
}

Author.cs

namespace MyWebsite.Models
{
    public class Author
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime SignUpDate { get; set; }
    }
}

3 个答案:

答案 0 :(得分:1)

尝试此操作是否有效。自从我为关系实体播种以来,我遇到了同样的问题。我的建议是尝试在代码中放入try catch,以查看是否存在任何异常

在您的Program.cs

using (var scope = host.Services.CreateScope())
{
  var services = scope.ServiceProvider;
  SeedData.Initialize(services).Wait();
}

然后像这样

public static async Task Initialize(IServiceProvider serviceProvider) {
  using (var context = new ApplicationDbContext(
                serviceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
            {
                if (!context.Posts.Any())
                {
                    post.Comments = comments;

                    await SeedPost(context);
                }
            }
}

您会看到我的Post实体具有评论列表,因此我还将评论列表分配到Post对象中,然后立即播种

您可以查看我的完整代码here

答案 1 :(得分:1)

第一次成功执行SaveChange()操作,但是第二次由于缺少作者的外键而添加帖子时出错,因此不执行该操作。 始终使用一个SaveChange!

必须将外键AuthorId添加到Post Model或将Author Object映射到Post.Author对象才能创建关系

 public static void Initialize(MyWebsiteContext context)
        {
            // Look for any authors; if none, seed DB.
            if (context.Author.Any())
            {
                return; // DB has already been seeded.
            }

            var authors = new Author[]
            {
                new Author{ FirstName="Terry",LastName="Pratchett",SignUpDate=DateTime.Parse("2019-04-01")},
                new Author{ FirstName="Neil",LastName="Gaiman",SignUpDate=DateTime.Parse("2019-03-02")},
            };

            foreach (Author a in authors)
            {
                context.Author.Add(a);
            }

            var posts = new Post[]
            {
                new Post{PostID=1,Title="Title of post 1" ,Author = authors[0] },
                new Post{PostID=2,Title="Title of post 2" ,Author = authors[0]},
                new Post{PostID=3,Title="Title of post 3" ,Author = authors[0]},
            };
            foreach (Post p in posts)
            {
                context.Post.Add(p);
            }
            context.SaveChanges();
        }

答案 2 :(得分:0)

原始代码中需要修复的两件事:

  1. 播种期间PostID的定义。这两个选项是a)删除该定义,或b)在SQL Server中显式打开IDENTITY_INSERThere讨论了第二种方法,但是出于我的目的,只需删除定义即可。

  2. Author对象映射到Post.Author。仅仅调用new Post{Title="Title of post 1"}是不够的;指定Author是必需的。

相关DbInitializer段:

            var posts = new Post[]
            {
                new Post{Title = "Title of post 1", Author = authors[0]},
                new Post{Title = "Title of post 2", Author = authors[0]},
                new Post{Title = "Title of post 3", Author = authors[1]},
            };

感谢所有帮助。