如何避免将重复项添加到由Seed方法导致的EntityFramework管理的数据库中?

时间:2014-08-15 20:51:35

标签: c# entity-framework duplicates seed asp.net-mvc-5.1

每次运行应用程序时,都会将相同的对象添加到数据库中(重复)。

我的Global.asax

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using WebApplication2.Migrations;
using WebApplication2.Models;


namespace WebApplication2 {
    public class MvcApplication : System.Web.HttpApplication {
        protected void Application_Start() {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Configuration>()); 
            //Database.SetInitializer(new DropCreateDatabaseAlways<ApplicationDbContext>());
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}

和我的Configuration.cs Seed方法:

namespace WebApplication2.Migrations
{
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;
    using WebApplication2.Models;

    internal sealed class Configuration : DbMigrationsConfiguration<WebApplication2.Models.ApplicationDbContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
            ContextKey = "WebApplication2.Models.ApplicationDbContext";
        }

        protected override void Seed(WebApplication2.Models.ApplicationDbContext context) {
            var persons = new List<Person> { 
         new Person{FirstName = "John", LastName = "Doe", CellNumber = "123-456-789", SecondaryPhoneNumber = "98873213", Address = "1street 2",BirthDate = DateTime.Now.Date, Pesel = "312312312", Notes = "Annoying"},
         new Person{FirstName = "Anna", LastName = "Doe", CellNumber = "113-456-789", SecondaryPhoneNumber = "98873213", Address = "1street 2",BirthDate = DateTime.Now.Date, Pesel = "548555672", Notes = "Less Annoying"}
        };

        persons.ForEach(person => context.Persons.AddOrUpdate(person));
        context.SaveChanges();

        var meetings = new List<Meeting>{
            new Meeting{PersonId = 1, Body = "Body of meeting", Date = DateTime.Now}
        };

        meetings.ForEach(meeting => context.Meetings.AddOrUpdate(meeting));
        context.SaveChanges();

        var statuses = new List<Status> {
            new Status{Name = "OK"},
            new Status {Name = "NOT_OK"}
        };

        statuses.ForEach(status => context.Statuses.AddOrUpdate(status));
        context.SaveChanges();

        }
    }
}

每次运行应用Seed都会添加重复记录:

enter image description here

我需要评论Seed方法的内容以防止添加重复项。

问题:(1)我应该更改什么才能运行Seed方法,以便在迁移后重新创建数据库?

编辑:

Seed方法中有评论:

  //  This method will be called after migrating to the latest version.

            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //

但我的方法不仅在迁移后被称为ALWAYS。为什么会这样?

6 个答案:

答案 0 :(得分:9)

this page (about halfway down)来自this answer

  

注意:向Seed方法添加代码是将固定数据插入数据库的众多方法之一。 另一种方法是向每个迁移类的Up和Down方法添加代码。 Up和Down方法包含实现数据库更改的代码。您将在“部署数据库更新”教程中看到它们的示例。

     

您还可以使用Sql方法编写执行SQL语句的代码。例如,如果您要将“预算”列添加到“部门”表并希望将所有部门预算初始化为$ 1,000.00作为迁移的一部分,则可以将以下代码行添加到该迁移的Up方法中:

     

Sql(&#34; UPDATE Department SET Budget = 1000&#34;);

您也可以考虑使用this answer中引用的AddOrUpdate方法,该方法也可以用于您的目的。

我很快改变了我从上面链接的答案中获得的代码,所以如果下面的代码存在问题,请耐心等待。我相信这个概念应该还是比较清楚的。

context.People.AddOrUpdate(c => c.PK, new Person() { PK = 0, FirstName = "John", ... })
context.People.AddOrUpdate(c => c.PK, new Person() { PK = 1, FirstName = "Anna", ... })

答案 1 :(得分:6)

您可以完全访问Seed方法中的上下文,因此您可以查询数据是否已存在。

例如,只有在表格为空时才可以对表进行播种...

protected override void Seed(WebApplication2.Models.ApplicationDbContext context) {

    if (!context.Persons.Any())
    {   
        var persons = new List<Person> { 
            new Person{FirstName = "John", LastName = "Doe", CellNumber = "123-456-789", SecondaryPhoneNumber = "98873213", Address = "1street 2",BirthDate = DateTime.Now.Date, Pesel = "312312312", Notes = "Annoying"},
            new Person{FirstName = "Anna", LastName = "Doe", CellNumber = "113-456-789", SecondaryPhoneNumber = "98873213", Address = "1street 2",BirthDate = DateTime.Now.Date, Pesel = "548555672", Notes = "Less Annoying"}
        };

        persons.ForEach(person => context.Persons.Add(person));
        context.SaveChanges();
    }

    if (!context.Meetings.Any())
    {
        var meetings = new List<Meeting>{
            new Meeting{PersonId = 1, Body = "Body of meeting", Date = DateTime.Now}
        };

        meetings.ForEach(meeting => context.Meetings.Add(meeting));
        context.SaveChanges();
    }

    if (!context.Statuses.Any())
    {
        var statuses = new List<Status> {
            new Status{Name = "OK"},
            new Status {Name = "NOT_OK"}
        };

        statuses.ForEach(status => context.Statuses.Add(status));
        context.SaveChanges();
    }

}

您也可以使用AddOrUpdate,但是您需要告诉EF如何使用第一个参数检查记录是否存在...

protected override void Seed(WebApplication2.Models.ApplicationDbContext context) {

    var persons = new List<Person> { 
        new Person{FirstName = "John", LastName = "Doe", CellNumber = "123-456-789", SecondaryPhoneNumber = "98873213", Address = "1street 2",BirthDate = DateTime.Now.Date, Pesel = "312312312", Notes = "Annoying"},
        new Person{FirstName = "Anna", LastName = "Doe", CellNumber = "113-456-789", SecondaryPhoneNumber = "98873213", Address = "1street 2",BirthDate = DateTime.Now.Date, Pesel = "548555672", Notes = "Less Annoying"}
    };

    persons.ForEach(person => context.Persons.AddOrUpdate(p => new { p.FirstName, p.LastName }, person));
    context.SaveChanges();

    var meetings = new List<Meeting>{
        new Meeting{PersonId = 1, Body = "Body of meeting", Date = DateTime.Now}
    };

    meetings.ForEach(meeting => context.Meetings.AddOrUpdate(m => m.Body, meeting));
    context.SaveChanges();

    var statuses = new List<Status> {
        new Status{Name = "OK"},
        new Status {Name = "NOT_OK"}
    };

    statuses.ForEach(status => context.Statuses.AddOrUpdate(s => s.Name, status));
    context.SaveChanges();

}

答案 2 :(得分:1)

  

问题:(1)我应该改变什么,所以Seed方法只会运行   迁移后重新创建数据库?

如果您只需要在创建数据库时播种数据。在这种情况下,您可以从CreateDatabaseIfNotExist Initialiser创建数据库初始化程序。然后在DatabaseInitialiser类中,您可以使用您的数据覆盖种子方法,而不是MigrationConfiguration类。更多信息可以在附件链接中找到。

Database Initialization Strategies in Code-First:

  

但我的方法不仅在迁移后被称为ALWAYS。为什么   所以?

在迁移配置中。每次数据库迁移发生时都会调用种子方法。这就是为什么你的种子方法一直被调用的原因。

答案 3 :(得分:0)

var paidOutType = new List<PaidOutType>
                {
                    new PaidOutType { PaidOutTypeID = 1, Code = "001", Description = "PAID OUT 1", PType = "1", Amount = 0, IsSalesSummery = true,DayFrom=1,DayTo=31 },
                    new PaidOutType { PaidOutTypeID = 2, Code = "002", Description = "PAID OUT 2", PType = "1", Amount = 0, IsSalesSummery = true,DayFrom=1,DayTo=31 },
                    new PaidOutType { PaidOutTypeID = 3, Code = "002", Description = "PAID OUT 3", PType = "1", Amount = 0, IsSalesSummery = true,DayFrom=1,DayTo=31 },
                };
                paidOutType.ForEach(u => smartPOSContext.PaidOutType.AddOrUpdate(u));
                smartPOSContext.SaveChanges();

答案 4 :(得分:0)

这对我有用

  1. 删除表格中的所有行
  2. 如果激活增量标识,则将其重置为0(seed()中指定的主键必须与数据库表中的主键匹配,以便它们不会重复)
  3. 在“种子”中指定主键&#39;方法
  4. 多次运行seed()方法,检查它们是否重复

答案 5 :(得分:-1)

首先,重置您的主键,以确保不会出现重复

"ServerName localhost:8080"

然后使用// reset identity autoincrement to 0 context.Database.ExecuteSqlCommand("DBCC CHECKIDENT('tableName', RESEED, 0)"); 方法播种数据

AddOrUpdate