2013-10-08 5 views
4

Я использую первый подход EF 5 Database в моем приложении MVC. все мои таблицы используют поле «Удалено», которое является логическим полем для отметки записи, удаляется.EF 5 Условное сопоставление

Я пытаюсь избавиться от необходимости проверять Deleted == false каждый раз, когда я запрашиваю свою базу данных. Очень простой способ сделать это - использовать условное отображение в файле edmx, где EF всегда возвращает данные, которые не удаляются. Это все хорошо.

Но проблема выполнения этого соответствия условий заключается в том, что, когда я хочу разрешить пользователю удалять какую-либо запись, например Адрес из своей адресной книги, у меня нет доступа к полю Delete из EF, поскольку я использовал его в условное отображение, и поэтому я должен искать другой вариант, позволяющий пользователю удалять запись.

Как я думал, это создать хранимую процедуру, обрабатывающую запрос удаления, и вызвать его, когда я хочу удалить запись.

Есть ли лучший способ сделать это? Можно ли сделать поле «Удалить» доступным, даже если оно используется в условном сопоставлении?

ответ

14

У меня есть рабочее решение для Soft Delete in Entity Framework Code First, которое может помочь.

Ключ в том, что вы добавляете дискриминатор для каждой модели, которую вы хотите иметь возможность мягкого удаления. В коде первым это делается так:

modelBuilder.Entity<Foo>().Map(m => m.Requires("IsDeleted").HasValue(false));

Это делает его невидимым для контекста, и поэтому вы должны сделать удаления с помощью SQL.

Если это эквивалент вашей «условного отображения» в базе данных Во-первых, то один из способов изменить SQL, чтобы переопределить SaveChanges и запустить SQL оттуда:

public override int SaveChanges() 
{ 
    foreach (var entry in ChangeTracker.Entries() 
      .Where(p => p.State == EntityState.Deleted 
      && p.Entity is ModelBase))//I do have a base class for entities with a single 
             //"ID" property - all my entities derive from this, 
             //but you could use ISoftDelete here 
    SoftDelete(entry); 

    return base.SaveChanges(); 
} 

private void SoftDelete(DbEntityEntry entry) 
{ 
    var e = entry.Entity as ModelBase; 
    string tableName = GetTableName(e.GetType()); 
    Database.ExecuteSqlCommand(
      String.Format("UPDATE {0} SET IsDeleted = 1 WHERE ID = @id", tableName) 
      , new SqlParameter("id", e.ID)); 

    //Marking it Unchanged prevents the hard delete 
    //entry.State = EntityState.Unchanged; 
    //So does setting it to Detached: 
    //And that is what EF does when it deletes an item 
    //http://msdn.microsoft.com/en-us/data/jj592676.aspx 
    entry.State = EntityState.Detached; 
} 

Метод, используемый для Get Table Name explained here

Так я и делал это. Вероятно, не имеет отношения к вашему базовому подходу баз данных в EF5, но теперь я перешел к его выполнению в хранимых процедурах. EF6 Code First генерирует CreateStoredProcedure вызовов в файлах миграции. Я заменяю их this.CreateDeleteProcedure("dbo.Foo_Delete", "[dbo].[Foos]");, что является вызовом по моему дополнительному методу:

public static class MigrationExtensions 
{ 
    internal static string DeleteSqlFormat 
    { 
     //I also hard delete anything deleted more than a day ago in the same table 
     get { return "DELETE FROM {0} WHERE IsDeleted = 1 AND DATEADD(DAY, 1, DeletedAt) < GETUTCDATE(); UPDATE {0} SET IsDeleted = 1, DeletedAt = GETUTCDATE() WHERE ID = @ID;"; } 
    } 

    internal static void CreateDeleteProcedure(this DbMigration migration, string procName, string tableName) 
    { 
     migration.CreateStoredProcedure(
         procName, 
         p => new 
         { 
          ID = p.Int(), 
         }, 
         body: 

          string.Format(MigrationExtensions.DeleteSqlFormat, tableName) 

        ); 
    } 

} 
+0

+1 Очень хорошее решение. –

+0

Это слово, которое я искал, «Мягкое удаление». Да, это кажется хорошим решением для кода. Скорее всего, я собираюсь создать динамический запрос в сохраненном proc и использовать сопоставление хранимых процедур в edmx и сопоставить хранимую процедуру, которую я создаю для Delete. Поэтому, когда я вызываю «Удалить» в контексте, он будет вызывать автоматическую картографию «Удалить хранимую процедуру». – Amila

+0

Впечатляющий, после поиска рабочего решения, я только что нашел его. Были некоторые незначительные проблемы при работе с 'GetTableName', версия, которую вы опубликовали в другой статье, нуждается в небольших доработках даже для компиляции. Но это не меняет того факта, что, действительно, этот подход с мягким удалением работает как шарм. –

Смежные вопросы