Код элемента 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);
        }
     }