Код элемента Entity Framework Первый метод AddOrUpdate insert Дублирующие значения
У меня есть простой объект:
public class Hall
{
[Key]
public int Id {get; set;}
public string Name [get; set;}
}
Затем в методе Seed
я использую AddOrUpdate
для заполнения таблицы:
var hall1 = new Hall { Name = "French" };
var hall2 = new Hall { Name = "German" };
var hall3 = new Hall { Name = "Japanese" };
context.Halls.AddOrUpdate(
h => h.Name,
hall1,
hall2,
hall3
);
Затем я запускаю консоль управления пакетами:
Add-Migration Current
Update-Database
Все в порядке: у меня три строки в таблице "Зал". Но если я запустил консоль управления пакетами Update-Database
снова, у меня уже есть пять строк:
Id Name
1 French
2 Japaneese
3 German
4 French
5 Japanese
Почему? Я думаю, что это должно быть три строки снова, а не пять. Я попытался использовать свойство Id
вместо Name
, но это не имеет значения.
UPDATE:
Этот код дает тот же результат:
var hall1 = new Hall { Id = 1, Name = "French" };
var hall2 = new Hall { Id = 2, Name = "German" };
var hall3 = new Hall { Id = 3, Name = "Japanese" };
context.Halls.AddOrUpdate(
h => h.Id,
hall1);
context.Halls.AddOrUpdate(
h => h.Id,
hall2);
context.Halls.AddOrUpdate(
h => h.Id,
hall3);
Также у меня есть последняя EntityFramework, установленная через nuget.
Ответы
Ответ 1
Хорошо, я ударил меня с клавиатуры в течение часа с этим. Если поле идентификатора таблицы является полем "Идентификация", то оно не будет работать, поэтому используйте для выражения expressionExpression. Я использовал свойство Name, а также удалил поле Id из инициализатора new Hall {...}
.
Эта настройка для кода OPs работала для меня, поэтому я надеюсь, что это кому-то поможет:
protected override void Seed(HallContext context)
{
context.Halls.AddOrUpdate(
h => h.Name, // Use Name (or some other unique field) instead of Id
new Hall
{
Name = "Hall 1"
},
new Hall
{
Name = "Hall 2"
});
context.SaveChanges();
}
Ответ 2
Этот код работает:
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(HallContext context)
{
context.Halls.AddOrUpdate(
h => h.Id,
new Hall
{
Id = 1,
Name = "Hall 1"
},
new Hall
{
Id = 2,
Name = "Hall 2"
});
context.SaveChanges();
}
Ответ 3
Я знаю, что это старый вопрос, но правильный ответ заключается в том, что если вы устанавливаете id # самостоятельно и хотите использовать AddOrUpdate, тогда вам нужно сказать EF/SQL, что вы не хотите, чтобы он генерировал идентификатор #.
modelBuilder.Entity<MyClass>().Property(p => p.Id)
.HasDatabaseGeneratedOption(System.ComponentModel
.DataAnnotations.Schema.DatabaseGeneratedOption.None);
Нижняя сторона этого заключается в том, что при вставке нового элемента вам нужно установить его Id, поэтому, если это выполняется динамически во время выполнения (вместо данных семени), вам нужно будет вычислить следующий идентификатор. Context.MyClasses.Max(c=>c.Id) + 1
работает хорошо.
Ответ 4
Это также может быть вызвано, если вы неправильно устанавливаете состояние Entity. Я продолжал получать следующую ошибку при запуске базы данных обновлений... "Последовательность содержит несколько совпадающих элементов".
Например, у меня были созданы повторяющиеся строки для каждой команды update-database (что, конечно же, не должно происходить при посеве данных), а затем следующая команда базы данных обновлений не будет работать вообще, поскольку она обнаружила больше чем одно совпадение (следовательно, ошибка последовательности, указывающая, что у меня есть несколько совпадающих строк). Это потому, что я переопределил SaveChanges в моем файле контекста с вызовом метода ApplyStateChanges...
public override int SaveChanges()
{
this.ApplyStateChanges();
return base.SaveChanges();
}
Я использовал ApplyStateChanges, чтобы гарантировать, что при добавлении графов объектов Entity Framework явно знает, находится ли объект в добавленном или измененном состоянии. Все объяснение того, как я использую ApplyStateChanges, можно найти здесь.
И это отлично работает (но остерегается!!)... если вы также размещаете базу данных с помощью миграции CodeFirst, то вышеупомянутый метод вызовет хаос для вызова AddOrUpdate() в методе семени. Поэтому прежде чем что-либо еще, просто проверьте файл DBContext и убедитесь, что вы не переопределяете SaveChanges выше, или вы получите второй экземпляр дубликатов данных, выполняющих команду update-database, а затем не будете работать вообще в третий раз, поскольку для каждого соответствующего элемента имеется более одной строки.
Когда дело доходит до этого, вам не нужно настраивать Id в AddOrUpdate()..., который побеждает всю цель простого и начального посева базы данных. Он отлично работает чем-то вроде:
context.Students.AddOrUpdate(
p => p.StudentName,
new Student { StudentName = "Bill Peters" },
new Student { StudentName = "Jandra Nancy" },
new Student { StudentName = "Rowan Miller" },
new Student { StudentName = "James O'Dalley" },
просто AS LONG, поскольку я не переопределяю метод SaveChanges в своем контекстном файле с вызовом ApplyStateChanges. Надеюсь, это поможет.
Ответ 5
Я обнаружил, что AddOrUpdate
отлично работает с полями, которые не являются идентификаторами. Если это работает для вас: context.Halls.AddOrUpdate(h => h.Name, hall1, hall2, hall3)
Возможно, вы захотите использовать имена Hall, такие как "French_test_abc_100", "German_test_abc_100" и т.д.
Это останавливает жестко закодированные тестовые данные, когда вы тестируете свое приложение.
Ответ 6
Если id объекта (hall) равен 0, это вставка. Я думаю, вам нужно дважды проверить поле id объектов вашего зала
Ответ 7
Является ли поле ID поле "Идентификация"? Я столкнулся с этой проблемой. Когда я удалил статус Identity из моего поля ID и установил идентификаторы, входящие в базу данных, это устранило проблему.
Это сработало для меня, поскольку это были справочные таблицы и, во всяком случае, не должны были быть полями идентичности.
Ответ 8
Я думаю, вероятно, что вам нужно отменить существующие миграции баз данных (т.е. начать свою базу данных с нуля) с помощью чего-то вроде "Update-Database TargetMigration: 0", за которым следует "Update-Database".
Как бы то ни было, вы не отбрасываете существующую таблицу или значения, вы просто добавляете/обновляете эти значения. Это должно произойти, чтобы получить желаемый результат.
Здесь хорошая ссылка для миграции EF: http://elegantcode.com/2012/04/12/entity-framework-migrations-tips/
Ответ 9
Я использовал поле ID как Identity/Key и добавлял атрибуты, чтобы не назначать идентификаторы сервером. Это решило проблему для меня.
public class Hall
{
[Key]
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id {get; set;}
public string Name [get; set;}
}
Ответ 10
Только для ответа Ciaren, приведенный ниже код сброса контекста ModelCreating помог мне решить аналогичные проблемы. Убедитесь, что вы изменили "ApplicationContext" на свое имя DbContext.
public class ApplicationContext : DbContext, IDbContext
{
public ApplicationContext() : base("ApplicationContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
Database.SetInitializer<ApplicationContext>(null);
base.OnModelCreating(modelBuilder);
}
}