Как изменить State.Modified на State.Added, но использовать новый ключ?

Всякий раз, когда объект, который наследует от HistoricalData, изменяется, я хочу сделать вставку вместо обновления.

Это абстрактный базовый класс с ключом {VersionID, ParentID}:

public abstract class HistoricalData
{
    public int VersionID { get; set; }
    public Guid ParentID { get; set; }
    public DateTime ValidFrom { get; set; }
}

Это мой подход в DbContext:

public override Task<int> SaveChangesAsync()
{
    foreach (var entry in ChangeTracker.Entries<HistoricalData>().Where(e => e.State == EntityState.Modified))
    {
        InsertInsteadOfUpdate(entry);
    }
    return base.SaveChangesAsync();
}

private void InsertInsteadOfUpdate(DbEntityEntry<HistoricalData> entry)
{
    // ValidFrom is not set manually -> Set it automatically to now
    if (entry.OriginalValues["ValidFrom"].Equals(entry.CurrentValues["ValidFrom"]))
    {
        entry.Entity.ValidFrom = DateTime.Now;
    }
    // Insert instead of Update
    entry.CurrentValues["VersionID"] = null;
    entry.State = EntityState.Added;
}

Я меняю VersionID, потому что это столбец идентификаторов, и я хочу, чтобы база данных создала новое значение для вставки.

Однако я получаю следующее исключение:

System.InvalidOperationException: свойство «VersionID» является частью ключевой информации объекта и не может быть изменено.

Если я не попытаюсь изменить VersionID, вставка завершится с ошибкой DuplicateKey Exception.

Есть ли способ изменить DbEntityEntry с Modified на Add с новым идентификатором?


person magnattic    schedule 09.04.2014    source источник
comment
Этот вопрос связан с моим предыдущим вопросом, но я использую другой подход, который привел к другой проблеме.   -  person magnattic    schedule 09.04.2014
comment
Вы пытались сначала установить для него значение «Отключено», а затем изменить идентификатор?   -  person JC Ford    schedule 09.04.2014
comment
@JC. Нет, хорошая идея. Я попробую.   -  person magnattic    schedule 09.04.2014
comment
Затем я получаю проблему: Member 'CurrentValues' cannot be called for the entity of type 'CustomerData' because the entity does not exist in the context. To add an entity to the context call the Add or Attach method of DbSet<CustomerData>. Есть ли другой способ сбросить VersionID? int не может быть обнулён:/   -  person magnattic    schedule 09.04.2014
comment
Когда сущность отсоединена, это просто объект. Так что, может быть, entity.VersionID = default(int)   -  person JC Ford    schedule 09.04.2014
comment
@JC. Я знаю об этом. Но я понятия не имею, как сбросить поле VersionID, чтобы оно создавалось базой данных при вставке. Если я оставлю все как есть, у меня снова возникнет проблема с DuplicateKey.   -  person magnattic    schedule 09.04.2014
comment
Если VersionID не имеет значения NULL, то его значение по умолчанию равно default(int) или 0. Если EF увидит столбец id с нулевым значением, я думаю, что он будет считаться новым.   -  person JC Ford    schedule 09.04.2014
comment
Извините, вы совершенно правы. Моя проблема заключалась в том, что столбец на самом деле не был столбцом идентификатора. (Оказывается, вы не можете изменить идентификатор столбца с помощью CF Migrations. Это автоматически завершится ошибкой.) Теперь EF будет полностью игнорировать VersionID, поэтому все, что мне нужно сделать, это установить State в Added. Если вы опубликуете свое решение в качестве ответа, я с радостью приму его.   -  person magnattic    schedule 09.04.2014
comment
Также следует отметить, что добавление сущностей таким образом не делает кэш недействительным. Поэтому, если я использую HistoricalData в качестве свойства коллекции/навигации в другом объекте, мне придется перезагружать его вручную. В моем случае: entry.Collection(x => x.Versions).Load();, где Versions — это коллекция HistoricalData.   -  person magnattic    schedule 09.04.2014
comment
Обнаружив, что объект был изменен, не могли бы вы клонировать объект и прикрепить его (для вставки?).   -  person Mike    schedule 09.04.2014