Soft Deletes (IsHistorical столбец) с EntityFramework - PullRequest
9 голосов
/ 21 декабря 2009

Я работаю с базой данных, в которой дизайнеры решили пометить каждую таблицу столбцом IsHistorical. Правильное моделирование не учитывается, и я не могу изменить схему.

Это вызывает некоторые трения при разработке экранов CRUD, которые взаимодействуют со свойствами навигации. Я не могу просто взять Продукт и затем отредактировать его EntityCollection. Я должен вручную написать IsHistorical проверки повсюду, и это сводит меня с ума.

Дополнения также ужасны, потому что до сих пор я написал все ручные проверки, чтобы увидеть, просто ли добавлено мягкое удаление, поэтому вместо добавления дублирующегося объекта я могу просто переключить IsHistoric.

Я рассмотрел три варианта:

  1. Изменение шаблонов t4 для включения проверок и синхронизации IsHistorical.

  2. Перехватывать удаления и добавления в ObjectContext, переключать столбец IsHistorical и затем синхронизировать состояние объекта.

  3. Подписаться на событие AssociationChanged и переключить там столбец IsHistorical.

Кто-нибудь имеет какой-либо опыт с этим или может порекомендовать самый безболезненный подход?

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

Замечание # 2 Ответ LukeLed технически верен, хотя вынуждает вас использовать действительно плохую модель для бедных, без графов. Проблема заключается в том, что теперь мне нужно вырвать все «удаленные» объекты из графа и затем вызвать метод Delete для каждого. Это действительно не спасет меня так много ручного церемониального кодирования. Вместо того, чтобы писать ручные проверки IsHistoric, я собираю удаленные объекты и перебираю их.

Ответы [ 3 ]

8 голосов
/ 22 декабря 2009

Я использую общий репозиторий в своем коде. Вы можете сделать это как:

public class Repository<T> : IRepository<T> where T : EntityObject
{
    public void Delete(T obj)
    {
        if (obj is ISoftDelete)
            ((ISoftDelete)obj).IsHistorical = true
        else
            _ctx.DeleteObject(obj);
    }

Ваш List() метод также будет фильтровать по IsHistorical.

EDIT:

ISoftDelete интерфейс:

public interface ISoftDelete
{
    bool IsHistorical { get; set; }
}

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

public partial class MyClass : EntityObject, ISoftDelete
{

}
5 голосов
/ 22 декабря 2009

Как я уверен, вы знаете, что не будет отличного решения этой проблемы, если вы не можете изменить схему. Учитывая, что вам не нравится опция Repository (хотя, мне интересно, если вы не торопитесь ее отклонить), вот лучшее, что я могу предложить:

  1. Ручка ObjectContext.SavingChanges
  2. Когда это событие срабатывает, проследите через ObjectStateManager в поисках объектов в удаленном состоянии. Если у них есть свойство IsHistorical, установите его и измените состояние объекта на измененное.

Это может быть сложно, когда дело доходит до ассоциаций / отношений, но я думаю, что это более или менее делает то, что вы хотите.

0 голосов
/ 02 мая 2013

Я использую шаблон репозитория также с кодом, аналогичным коду LukLed, но я использую отражение, чтобы увидеть, есть ли свойство IsHistorical (так как это согласованное соглашение об именах):

public class Repository<TEntityModel> where TEntityModel : EntityObject, new() 
{
       public void Delete(TEntityModel entity)
        {
            // see if the object has an "IsHistorical" flag
            if (typeof(TEntityModel).GetProperty("IsHistorical") != null);
            {
                // perform soft delete
                var historicalProperty = entity.GetType().GetProperty("IsHistorical");
                historicalProperty.SetValue(entity, true, null);
            }
            else
            {
                // perform real delete
                EntityContext.DeleteObject(entity);
            }

            EntityContext.SaveChanges();                
        }
}

Использование тогда просто:

using (var fubarRepository = new Repository<Fubar>)
{
   fubarRepository.Delete(someFubar); 
}

Конечно, на практике вы расширяете это, чтобы разрешить удаление, передавая PK вместо инстанцированного объекта и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...