Удаление сущностей - QualitySolution/QSProjects GitHub Wiki

В библиотеке имеется механизм удаления, который автоматически находит ссылки из всех зависимых объектов на удаляемый объект и может либо очистить ссылку, либо удалить ссылающийся объект вместе с удаляемым. В целом все это можно было бы реализовать просто прописыванием правил на уровне базы данных, но тогда пользователю не очевидно, что ,удаляя один объект, он также удаляет еще 100 связанных. Поэтому, механизм нужен в первую очередь, чтобы отобразить все действия по удалению пользователю. Также, он позволяет при удалении выполнить что-то из кода, например какой-то перерасчет.

Основные классы системы удаления находятся в пространстве имен QS.Deletion.

Настройка модуля удаления

Для всех старых компонентов, использующих напрямую статические классы QSMain и DeleteHelper, конфигурацию необходимо делать через статический класс DeleteConfig, с использованием старого API. Если проект использует только новый диалог MVVM и удаление через IDeleteEntityService, использовать статические классы нет необходимости. Можно в класс сервиса напрямую передать конфигурацию, создав класс QS.Deletion.Configuration.DeleteConfiguration и настроив его.

Ниже показаны примеры настройки через статический класс, настройка DeleteConfiguration происходит аналогично.

Примеры настройки

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

DeleteConfig.AddHibernateDeleteInfo<Organization>();

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

Очистка ссылки

DeleteConfig.AddHibernateDeleteInfo<Organization>()
	    .AddClearDependence<Employee>(x => x.Organization);

В этом примере добавляется зависимость класса "Сотрудник" от класса "Организация". Эта настройка говорит системе удаления что при удалении организации, надо найти всех сотрудников у которых удаляемая организация указана в свойстве x.Organization и установить это свойство в null.

Удаление зависимого объекта

DeleteConfig.AddHibernateDeleteInfo<Organization>()
	    .AddDeleteDependence<Employee>(x => x.Organization);

Тоже самое что и в предыдущем примере, только на этот раз сотрудники, у которых в поле организация указана удаляемая организация, будет сам удален. Обратите внимание, что все правила удаления тянутся по цепочке, то есть если для удаления сотрудника настроено удаление еще чего-то, оно тоже будет удалено и т.д. Пока все зависимые объекты не будут удалены.

Удаление объекта из коллекции.

DeleteConfig.AddHibernateDeleteInfo<Employee> ()
	    .AddRemoveFromDependence<Organization> (x => x.Employees);

В примере показано как настроить удаление объекта из коллекции, находящейся родительском объекте. Это позволяет создать правило для тех случаев, когда коллекции не инверсны, то есть в дочернем объекте нет прямой ссылки\свойства его родителя. Если коллекция инверсна, лучше в правилах удаления указывайте ссылку на свойство в дочернем объекте.

DeleteConfig.AddHibernateDeleteInfo<Employee> ()
	    .AddRemoveFromDependence<Organization> (x => x.Employees, x => x.RemoveEmployee);

Второй вариант позволяет удалить объект из коллекции, вызовом метода метод x.RemoveEmployee. Это позволяет при удалении объекта из коллекции дополнительно произвести какие то действия, например что-то пересчитать.

Каскадное удаление

DeleteConfig.AddHibernateDeleteInfo<Document> ()
	    .AddDeleteCascadeDependence (x => x.Operation);

В некоторых случаях нам может понадобится удалять вместе с ними объект, на который мы сами ссылаемся. Например, у нас есть документ, который создает операцию и на нее ссылается. Операция не должна существовать без документа, поэтому удаляя документы мы должны удалить также операцию.

Подклассы и наследование

DeleteConfig.AddHibernateDeleteInfo<Document>().HasSubclasses();

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

Минимальная настройка AutoFac

var builder = new ContainerBuilder();
IContainer container = null;
builder.Register((ctx) => new AutofacViewModelsGtkPageFactory(container)).As<IViewModelsPageFactory>();
builder.RegisterType<GtkWindowsNavigationManager>().AsSelf().As<INavigationManager>().SingleInstance();
builder.RegisterType<DeleteEntityGUIService>().AsSelf();
builder.Register(x => DeleteConfig.Main).AsSelf();// Здесь можно взять собственный а не глобальный конфиг удаления.
builder.RegisterType<GtkMessageDialogsInteractive>().As<IInteractiveMessage>();
builder.RegisterType<GtkQuestionDialogsInteractive>().As<IInteractiveQuestion>();
builder.RegisterModule(new DeletionAutofacModule()); // Подгружаем настройки самого модуля удаления
builder.Register(ctx => new ClassNamesBaseGtkViewResolver(Assembly.GetAssembly(typeof(DeletionView)))).As<IGtkViewResolver>();
container = builder.Build();

Использование сервиса

var deleteService = container.Resolve<DeleteEntityGUIService>();
var deletion = deleteSerive.DeleteEntity(objectClass, id); //Запуск удаления

Тестирование настроек удаления

В библиотеке QS.Testing имеются методы хелперы, позволяющие организовать тестирование настроек удаления в своем проекте. Тесты позволяют находить пропущенные, не настроенные классы и ссылки на классы.

Пример того как использовать в своем проекте эти хелперы можно посмотреть тут https://github.com/QualitySolution/Workwear/blob/master/WorkwearTest/Deletion/ConfigTests.cs

Имеющиеся тесты

  • DeleteItemsTypesTest - Проверяет что тип свойства ссылки в правилах удаления соответствует удаляемому объекту
  • ClearItemsTypesTest - Аналогично предыдущему, только для правил очистки
  • DeleteRuleExisitForNHMappedClasssTest - Проверка что все классы, указанные в мапинге NHibernate имеют правила удаления
  • DependenceRuleExisitForNHMappedEntityRelationTest - Проверка всех ссылок на другие классы, имеют правила удаления
  • CascadeDependenceRuleExisitForNHMappedEntityRelationTest - Проверяет что все требуемые каскадные зависимости прописаны
  • NHMappedCollectionsAllInOneTest - Проверяем не инверсные коллекции на наличия правил удаления
  • DeleteRules_ExistTitle_Test - Проверка что все классы, указанные в настройках удаления имеют свойство Title или Name, нужно для отображения в диалоге удаления.
  • DeleteRules_ExistAppellativeAttribute_Test - Проверка что все классы имеют атрибут AppellativeAttribute. Нужно для отображения в диалоге удаления

Игнорирование

Иногда мы не хотим создавать правила удаления для каких нибудь классов, чтобы тесты не падали, а пропускали такие классы, их можно добавить в список игнорирования.

AddIgnoredClass<Employee>("Текст причины.");

Аналогичным способом можно игнорировать отсутствие правил удаления для конкретного свойства.

AddIgnoredProperty<Employee>(x => x.Profession, "Текст причины.");

Так же можно пропустить проверку конкретной коллекции.

AddIgnoredCollection<Client>(x => x.Accounts, "Текст причины.");

Требование каскадного удаления

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

DeleteConfig.AddHibernateDeleteInfo<Operation>()
	    .RequiredCascadeDeletion();
⚠️ **GitHub.com Fallback** ⚠️