C# 如何避免因种子方法而向EntityFramework管理的数据库添加重复项?
每次运行应用程序时,都会将相同的对象添加到数据库中(重复) 我的C# 如何避免因种子方法而向EntityFramework管理的数据库添加重复项?,c#,entity-framework,duplicates,seed,asp.net-mvc-5.1,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 WebApplic
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);
}
}
}
每次运行应用程序Seed
时,都会添加重复记录:
我需要对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" }
// );
//
//迁移到最新版本后将调用此方法。
//您可以使用DbSet.AddOrUpdate()助手扩展方法
//避免创建重复的种子数据。例如。
//
//context.People.AddOrUpdate(
//p=>p.FullName,
//新人{FullName=“安德鲁·彼得斯”},
//新人{FullName=“Brice Lambson”},
//新人{FullName=“Rowan Miller”}
// );
//
但我的方法总是被调用,而不仅仅是在迁移之后。为什么会这样?来源,来源于
注意:向Seed方法添加代码是将固定数据插入数据库的多种方法之一另一种方法是向每个迁移类的Up和Down方法添加代码。Up和Down方法包含实现数据库更改的代码。您将在部署数据库更新教程中看到它们的示例
您还可以使用SQL方法编写执行SQL语句的代码。例如,如果要将预算列添加到部门表中,并希望在迁移过程中将所有部门预算初始化为$1000.00,则可以将以下代码行添加到该迁移的Up方法中:
Sql(“更新部门设置预算=1000”)
您还可以考虑使用中引用的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", ... })
您可以在
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();
}
}
问题:(1)我应该更改什么以使种子方法只运行到
迁移后重新创建数据库
如果只需要在创建数据库时为数据设定种子。在这种情况下,您可以从CreateDatabaseIfNotExist Initialiser创建数据库初始化器。然后,在DatabaseInitialiser类中,您可以使用其中的数据而不是MigrationConfiguration类重写Seed方法。更多信息可以在附加的链接中找到
但我的方法总是被调用,而不仅仅是在迁移之后。为什么
那么
在迁移配置中。每次数据库迁移时都会调用seed方法。这就是一直调用seed方法的原因 var paidOutType=新列表
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();
{
新PaidOutType{PaidOutTypeID=1,Code=“001”,Description=“PaidOut 1”,PType=“1”,Amount=0,IsSalesSummery=true,DayFrom=1,DayTo=31},
新PaidOutType{PaidOutTypeID=2,Code=“002”,Description=“PaidOut 2”,PType=“1”,Amount=0,IsSalesSummery=true,DayFrom=1,DayTo=31},
新PaidOutType{PaidOutTypeID=3,Code=“002”,Description=“PaidOut 3”,PType=“1”,Amount=0,IsSalesSummery=true,DayFrom=1,DayTo=31},
};
ForEach(u=>smartPOSContext.paidOutType.AddOrUpdate(u));
smartPOSContext.SaveChanges();
这对我很有效
首先,重置您的主键,以确保没有重复的键
// reset identity autoincrement to 0
context.Database.ExecuteSqlCommand("DBCC CHECKIDENT('tableName', RESEED, 0)");
然后使用AddOrUpdate
方法对数据进行种子设定
context.People.AddOrUpdate(new Person
{
Id = 1,
Name = "John Doe"
});
我现在使用了
AddOrUpdate
,但它仍然添加了重复项。我只想让它在迁移后运行seed方法,从scratch重新创建数据库。当您不知道数据的主键时,似乎可以更好地解释如何使用AddOrUpdate
方法。为什么要明确定义Id
(PK)?实体框架不应该这样做吗?您必须以某种方式通知实体框架您不需要这些重复项。最简单的方法是提供密钥。在前面的评论中,我包含了一个链接,该链接应该允许您告诉EntityFramework使用任意字段查找现有记录,但我觉得在我的答案中包含该链接会增加一些不必要的复杂性。也许我做那个决定是错的。但您是对的,实体框架将自行分配主键(只要您不这样做),这是更正确的方法。请你看一下OP中的编辑,好吗?我不知道为什么,但在我的情况下,它仍然很高兴地添加了重复项(请参见OP中的代码)I usdAddOrUpdate
。更新了您如何使用AddOrUpdate
的答案,但迁移只在模型更改时发生,而不是每次运行时发生?或者是吗?在所附的链接中,还有一个我没有提到的初始化器,MigratedBtolatesVersion。这与您在configuration.csi中使用的类似。在上面的链接中,它没有提到MigratedBtolatesVersion initi
// reset identity autoincrement to 0
context.Database.ExecuteSqlCommand("DBCC CHECKIDENT('tableName', RESEED, 0)");
context.People.AddOrUpdate(new Person
{
Id = 1,
Name = "John Doe"
});