2010-02-19 30 views
9

我有一个名为“Customer”的对象,它将在其他表中用作外键。如何查找是否可以删除引用的对象?

的问题是,我想知道,如果“客户”可以被删除(即,它不被任何其他表引用)。

这可能与Nhibernate?

+0

你说'Customer'在“其他表”中所引用。复数的意图是什么?即,是从多个其他实体类引用的客户。 (答案影响可能的解决方案。) – 2010-02-19 08:21:14

+0

@Jorn,是的,它在很多其他表格中被引用。 – 2010-02-19 09:14:08

回答

5

你问什么是找到Customer PK值的存在被引用的表FK列英寸 有很多方法,你可以去一下:

  1. 为kgiannakakis指出,尝试做删除,如果抛出一个异常回滚。有效但丑陋,无用。这也要求您在数据库中设置CASCADE =“RESTRICT”。该解决方案有,你必须尝试删除对象来找出你不能

  2. 地图引用Customer作为收藏品,然后为每个集合的实体,如果他们Count > 0则不允许删除的缺点。这很好,因为只要映射完成,这对于模式更改是安全的。这也是一个不好的解决方案,因为必须进行额外的选择。

  3. 具有执行像bool IsReferenced(Customer cust)查询的方法。好,因为你可以有一个你想要的时候使用的单个查询。不太好,因为它可能容易因模式和/或域更改而导致错误(取决于您将执行的查询类型:sql/hql/criteria)。

  4. 在类它自与像<property name="IsReferenced" type="long" formula="sql-query that sums the Customer id usage in the referenced tables" />的映射元素A计算的属性。好,因为它是一个快速解决方案(至少和你的数据库一样快),不需要额外的查询。不太好,因为它容易发生模式更改,因此当您更改数据库时,不要忘记更新此查询。

  5. 疯狂溶液:创建模式绑定视图,使得计算。在需要时对其进行查询。好,因为它的模式绑定并且不太容易发生模式更改,这很好,因为查询很快,不太好,因为您仍然需要执行额外的查询(或者将解决方案4中的视图结果映射到该映射)。

2,3,4都还不错,因为你也可以投射这种行为,以您的UI(不允许删除)

个人而言,我会去为4,3,5与偏好

+1

这是一个很好的答案,很难回答更具体的问题,因为你的情况细节不是很清楚。对你的简短回答是“是”。你可以想象在你的数据库上运行的任何查询都可以在nHibernate中以某种方式进行(如果你正在使用HQL,则使用HQL)。 – 2010-02-25 23:33:59

1

这是不可能的。假设您的域名模型包含客户的相关对象,例如地址,订单等。您应该使用specification pattern

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 
    } 
} 

编辑补充:

也许最简单的方法是创建一个执行此检查存储过程并删除之前调用它。你可以从NHibernate访问一个IDbCommand(ISession.Connection.CreateCommand()),这样这个调用就是数据库不可知的。

另请参阅对this question的回应。

0

一个天真的解决方案将使用一个事务。开始一个事务并删除该对象。异常会通知您该对象无法删除。无论如何,做一个回滚。

2

在实体和关系中思考而不是表和外键,存在以下不同情况:

  • 客户拥有建立客户的一部分的一对多关系,例如他的电话号码。它们也应该通过级联方式删除。
  • 客户有一对多或多对多的关系,这不是客户的一部分,但他们是客户知道/可以访问的。
  • 其他一些实体与客户有关系。它也可以是任意类型的(它不是数据库中的外键)。例如客户的订单。订单不被客户所知。这是最难的情况。

据我所知,NHibernate没有直接的解决方案。有元数据API,它允许您在运行时探索映射定义。恕我直言,这是做错的方法。

在我看来,业务逻辑的责任是验证一个实体是否可以删除或不。 (即使存在确保数据库完整性的外键和约束,它仍然是业务逻辑)。

我们实现了在删除实体前调用的服务。软件的其他部分为某些类型注册。他们可以否决删除(例如通过抛出异常)。

例如,订单系统注册删除客户。如果客户应该被删除,订单系统会搜索该客户的订单,并在找到订单时抛出。

+0

你让我在业务逻辑中考虑这个问题 – 2010-03-02 10:15:20

4

我想知道是否可以删除“客户”(即,它不在任何其他表中引用)。

确定客户是否可以删除并不是真正的数据库责任。这是业务逻辑的一部分。

您要求检查数据库上的参照完整性。

在非OOP世界中可以。但是当处理对象时(像你一样),你最好把逻辑添加到你的对象中(对象有状态和行为; DB--只有状态)。

所以,我会添加一个方法到客户类,以确定它是否可以删除或不。这样你可以正常(单元)测试功能

例如,假设我们有一条规则如果客户没有订单并且未参与论坛,则只能将其删除。

然后,你将有类似这样的客户对象(最简单可行的情况下):

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的删除相关的订单和其他协会。


注:当然上面的例子只是最简单的说明性解决方案。您可能想要制定一条规则part of the validation,在删除对象时应执行该规则。

+1

你正在通过调用[collection] .Count属性(至少)2个额外的选择。另外,形成的单元测试(或不存在的)会通过一个条件。这可以通过应用数据库约束来保存!它总是一个很好的做法是,后端不依赖于前端业务逻辑数据的完整性 – Jaguar 2010-03-05 11:57:17

+0

您可以通过使用预先抓取或其他方式微调SQL测绘,目的是验证这个想法。至于'这可以通过应用数据库约束来保存' - 我提到它也应该是验证的一部分。 – 2010-03-06 00:41:45

+0

我会争辩说,检查数据库参照完整性是**不是**业务逻辑的一部分 - 我认为只有当您的程序是数据库程序时才是这种情况。 – fostandy 2016-03-29 00:16:17

相关问题