Как найти, может ли ссылочный объект быть удален?

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

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

Действительно ли это возможно с Nhibernate?

10
задан Brian Tompsett - 汤莱恩 6 July 2015 в 11:45
поделиться

6 ответов

Вы спрашиваете о существовании значения PK клиента в столбце FK, на который ссылаются таблицы. Есть много способов сделать это:

  1. как заметил Кгианнакакис, попробуйте выполнить удаление и, если возникнет исключение, откат. Эффективно, но некрасиво и бесполезно. Это также требует, чтобы вы установили CASCADE = "RESTRICT" в вашей базе данных. У этого решения есть недостаток, заключающийся в том, что вам нужно попытаться удалить объект, чтобы выяснить, что вы не можете

  2. сопоставить сущности, которые ссылаются на Customer как коллекции, а затем для каждой коллекции, если их Count > 0 , то удаление не разрешено. Это хорошо, потому что это безопасно от изменений схемы, пока отображение завершено. Это также плохое решение, потому что придется сделать дополнительный выбор.

  3. Имейте метод, выполняющий запрос типа bool IsReferenced (Customer cust) .Хорошо, потому что у вас может быть один запрос, который вы будете использовать, когда захотите. Не так хорошо, потому что он может быть подвержен ошибкам из-за изменений схемы и / или домена (в зависимости от типа запроса, который вы будете выполнять: sql / hql / критериям).

  4. Вычисляемое свойство самого класса с элементом сопоставления, например . Хорошо, потому что это быстрое решение (по крайней мере, так же быстро, как ваша БД), никаких дополнительных запросов. Не так хорошо, потому что он подвержен изменениям схемы, поэтому, когда вы меняете свою БД, вы не должны забывать обновлять этот запрос.

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

2,3,4 также хороши, потому что вы также можете проецировать это поведение на свой интерфейс (не разрешать удаление)

Лично я бы выбрал 4,3,5 с этим предпочтением

5
ответ дан 4 December 2019 в 00:24
поделиться

Возможно, стоит посмотреть на свойство cascade, в частности all-delete-orphan в ваших файлах hbm.xml, и это может решить проблему.

См. здесь, 16.3 - Каскадный жизненный цикл

0
ответ дан 4 December 2019 в 00:24
поделиться

Это невозможно напрямую. Предположительно, ваша доменная модель включает связанные объекты Customer, такие как Addresses, Orders и т.д. Для этого вам следует использовать спецификационный шаблон.

public class CustomerCanBeDeleted
{

    public bool IsSatisfiedBy(Customer customer)
    {
        // Check that related objects are null and related collections are empty
        // Plus any business logic that determines if a Customer can be deleted
    }
}

Отредактировано для добавления:

Возможно, самым простым методом будет создание хранимой процедуры, выполняющей эту проверку, и ее вызов перед удалением. Вы можете получить доступ к IDbCommand из NHibernate (ISession.Connection.CreateCommand()), чтобы вызов не зависел от базы данных.

См. также ответы на этот вопрос.

1
ответ дан 4 December 2019 в 00:24
поделиться

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

0
ответ дан 4 December 2019 в 00:24
поделиться

Я хочу знать, можно ли удалить «Заказчик» (т. Е. На него нет ссылок в других таблицах).

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

Вы просите проверить ссылочную целостность в базе данных.

Это нормально в мире без ООП. Но при работе с объектами (например, вы) вам лучше добавить логику к своим объектам ( объекты имеют состояние и поведение; БД - только состояние ).

Итак, я бы добавил метод к классу Customer, чтобы определить, можно ли его удалить или нет. Таким образом вы можете правильно (единично) протестировать функциональность .

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

Тогда у вас будет объект Customer, подобный этому (самый простой из возможных случаев):

public class Customer
{
    public virtual ISet<Order> Orders { get; protected set; }
    public virtual ISet<ForumPost> ForumPosts { get; protected set; }

    public virtual bool CanBedeleted
    {
        get
        {
            return Orders.Count == 0 && ForumPosts.Count == 0
        }
    }
}

Это очень чистый и простой дизайн, который прост в использовании, тестировании и не сильно зависит от NHibernate или базовой базы данных.

Вы можете использовать его так:

if (myCustomer.CanBeDeleted)
    session.Delete(mycustomer)

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


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

4
ответ дан 4 December 2019 в 00:24
поделиться

Если мыслить сущностями и отношениями, а не таблицами и внешними ключами, то возникают следующие ситуации:

  • Клиент имеет отношение «один ко многим», которое составляет часть клиента. , например, его номера телефонов. Их также следует удалить каскадом.
  • У клиента есть отношения «один ко многим» или «многие ко многим», которые не являются частью клиента, но они известны / достижимы для покупателя.
  • К Заказчику имеет отношение какое-то другое лицо. Это также может быть любой тип (который не является внешним ключом в базе данных). Например заказы заказчика. Заказ не известен заказчику. Это самый тяжелый случай.

Насколько мне известно, прямого решения от NHibernate нет. Существует API метаданных, который позволяет вам исследовать определения сопоставления во время выполнения. ИМХО, это неправильный способ.

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

Мы реализовали сервис, который вызывается перед удалением объекта. Другие части программного обеспечения регистрируются для определенных типов. Они могут наложить вето на удаление (например, выбрасывая исключение).

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

2
ответ дан 4 December 2019 в 00:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: