哪个 ORM 支持多行更新和删除
Posted
技术标签:
【中文标题】哪个 ORM 支持多行更新和删除【英文标题】:Which ORM Supports Multiple row Updates and Deletes 【发布时间】:2009-12-08 14:53:36 【问题描述】:我有一个查询删除所有标记为删除的行。表中有一个名为 IsDeleted 的列。如果该行与不同表中的所有相关行一起被删除,则它是一个布尔数据类型。
如果文章行被标记为删除,那么文章cmet,投票也应该被删除。哪个 ORM 可以有效地处理这个问题?
编辑
我在 C# .NET 中需要这个
【问题讨论】:
您使用什么语言和框架?答案很大程度上取决于您使用的是 Java、.Net 还是 Python 等 【参考方案1】:DataObjects.Net 提供了一个中间解决方案:
目前它不能对查询选择的实体执行服务器端删除。这将在某一天实施,但目前还有另一种解决方案。 另一方面,它支持所谓的通用批处理:如果可能的话,它发送的查询一次最多分批发送 25 个项目。 “可能”的意思是“现在不需要查询结果”。这对于创建、更新和删除几乎总是正确的。由于此类查询总是导致单个(或很少,如果有继承)查找操作,因此它们非常便宜。如果它们是批量发送的,SQL Server 可以缓存整个批量的计划,而不仅仅是那里的单个查询。所以这是非常快的,虽然还不理想:
目前 DO4 不使用 IN (...) 来优化此类删除。 目前还不支持异步批处理执行。完成后(我希望这将在一个月左右完成),它在 CUD(CRUD 的一个子集)操作上的速度将与 SqlBulkCopy 几乎相同(~= 1.5 ... 2 倍于现在) .因此,在 DO 批量删除的情况下,如下所示:
var customersToRemove =
from customer in Query<Customer>.All
where customer.IsDeleted
select customer;
foreach (customer in customersToRemove)
customer.Remove(); // This will be automatically batched
我可以说出这种方法的一个好处:任何这样的对象都能够对删除做出反应;会话事件订阅者也将收到有关每次删除的通知。因此,任何与删除相关的常见逻辑都将按预期工作。如果在服务器上执行这样的操作,这是不可能的。
软删除代码必须如下所示:
var customersToRemove =
from customer in Query<Customer>.All
where ...
select customer;
foreach (customer in customersToRemove)
customer.IsRemoved = true; // This will be automatically batched
显然,这种方法比批量服务器端更新要慢。根据我们的估计,在最坏的情况下([bigint Id, bigint Value] 表,聚集主索引,没有其他索引),我们现在拥有的速度比真正的服务器端删除慢 5 倍;在实际情况下(更多列、更多索引、更多数据),它现在必须带来相当的性能(即慢 2-3 倍)。异步批处理执行将进一步改善这一点。
顺便说一句,我们在ORMBattle.NET 与各种 ORM 框架的实体共享了批量 CUD 操作的测试。请注意,那里的测试不使用批量服务器端更新(实际上,这样的测试将是对数据库性能而不是 ORM 的测试);相反,他们测试 ORM 是否能够优化这一点。无论如何,如果您正在评估多个 ORM 工具,那里提供的信息 + test code 可能会有所帮助。
【讨论】:
【参考方案2】:通常,如果您已经在使用 IsDeleted 标志范例,则应用程序对象模型通常会忽略这些项目,这是有效且可靠的,因为不需要检查引用完整性(无级联),并且没有数据被永久销毁。
如果您希望定期清除 IsDeleted 行,那么使用本机 SQL 在 RDBMS 中将这些行安排为批处理作业会更有效,只要您以正确的顺序删除内容,以免影响参照完整性。如果您不在数据库级别强制执行引用完整性,那么顺序就无关紧要。
即使多年来在我所有的数据库设计中都具有强大的引用完整性和约束,我从未使用过级联 RI——它在我的设计中从来都不是可取的。
【讨论】:
【参考方案3】:NHibernate 支持 HQL(面向对象的Hibernate Query Language)更新和删除。
this Blog Post by Fabio Maulo和this Blog Post by Ayende Rahien中有一些例子。
它可能看起来像这样:
using (var session = OpenSession())
using (var tx = s.BeginTransaction())
session
.CreateQuery("delete from Whatever where IsDelete = true")
.ExecuteUpdate();
tx.Commit();
注意:这不是 SQL。这是包含类名和属性名的 HQL,它可以转换为(几乎)任何数据库。
【讨论】:
【参考方案4】:哪个 ORM 支持基于“标准”的删除...我使用过的两个(Propel、Doctrine)。我认为几乎所有人都会这样做,除非它们处于开发的早期,这是非常基本的事情。但是您使用的是什么语言?
就您的删除级联而言,最好在数据库级别使用外键实现。大多数 RDBMS 都支持这一点。如果您使用的东西不是某些 ORM 实现的,如果支持不可用。但我的建议是只使用支持它的 RDBMS。从长远来看,它会少一些头痛。
【讨论】:
如果您想删除所有太旧(> 5 年)的日志,那么 FK 的用处很小。我预计这可能是一个类似的案例。【参考方案5】:我正在使用 LLBLgen,它可以进行级联删除。您可能想尝试一下,它非常好。 例子。从 rolenames[] 中的所有角色中删除 username[] 中的所有用户
string[] usernames;
string[] rolenames;
UserRoleCollection userRoles = new UserRoleCollection ();
PredicateExpression filter = new PredicateExpression();
filter.Add(new FieldCompareRangePredicate(UserFields.logincode, usernames));
filter.AddWithAnd(new FieldCompareRangePredicate(RoleFields.Name, rolenames));
userRoles.DeleteMulti(filter)
【讨论】:
我可以这样做吗? userRoles.DeleteMulti('查询到这里')【参考方案6】:大多数 ORM 将允许您提供 SQL 提示,或在其框架内执行 SQL。
例如,您可以使用 LINQ 中的ExecuteQuery
方法来做您想做的事。这是一个关于在 LINQ 中使用自定义 sql 的简短教程。
http://weblogs.asp.net/scottgu/archive/2007/08/27/linq-to-sql-part-8-executing-custom-sql-expressions.aspx
我希望实体框架也允许它,但我从未使用过它,但你可以查看它。
基本上,找到一个具有您需要的功能的 ORM,然后您可以询问如何在您选择的 ORM 中执行此查询。我认为为这一功能选择 ORM 是有风险的,因为选择时还有许多其他因素。
【讨论】:
以上是关于哪个 ORM 支持多行更新和删除的主要内容,如果未能解决你的问题,请参考以下文章
利用jquery.ajax在jsp页面动态生成table,可以增加修改,并支持一行和多行删除