NHibernate一次性删除示例

时间:2014-09-08 02:06:12

标签: c# nhibernate

我试图让NHibernate删除一个发出单个delete语句或多个语句的集合。问题是,它在生成一些"获取当前状态"之后生成删除语句。查询,或者它只是将子项的parent_id设置为null并且不会删除它们(并且仍会生成这些读取)。

表: TestP([id] int not null; [name] nvarchar(50)) TestC([id] int not null; [id_p] int null; [other] nvarchar(50))

初始数据

insert into testp (id, name) values(1,'dad')

delete from testc

insert into testc (id, id_p, other) values(1, 1,'son 1')
insert into testc (id, id_p, other) values(2, 1,'son 2')

实体

public class Testp
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }

    public virtual ICollection<Testc> Children { get; set; }
}

public class Testc
{
    public virtual int Id { get; set; }
    public virtual int IdP { get; set; }
    public virtual string Other { get; set; }
}

映射

public class TestpMap : ClassMapping<Testp>
{

    public TestpMap()
    {
        Schema("dbo");
        Lazy(true);
        Id(x => x.Id, map => map.Generator(Generators.Assigned));
        Property(x => x.Name);

        Bag(x => x.Children, mapping =>
        {
            mapping.Key(k => k.Column("id_p"));
            mapping.Cascade(Cascade.DeleteOrphans|Cascade.All);
        },
        r => r.OneToMany());
    }
}

public class TestcMap : ClassMapping<Testc>
{
    public TestcMap()
    {
        Schema("dbo");
        Lazy(true);
        Id(x => x.Id, map => map.Generator(Generators.Assigned));
        Property(x => x.Other);
    }
}

测试1

using (var tx = session.BeginTransaction())
        {
            var test = session.Query<Testp>().First();
            test.Children.Clear();

            test.Children.Add(new Testc(){Id=103,Other="nuevo"});

            tx.Commit();
        }

这将生成以下SQL:

/* [expression] */select TOP (1) testp0_.Id as Id1_, testp0_.Name as Name1_ from dbo.Testp testp0_
go
exec sp_executesql N'/* load one-to-many engage5_html_generator.Testp.Children */ SELECT children0_.id_p as id3_1_, children0_.Id as Id1_, children0_.Id as Id0_0_, children0_.Other as Other0_0_ FROM dbo.Testc children0_ WHERE children0_.id_p=@p0',N'@p0 int',@p0=1
go
exec sp_executesql N'/* get current state engage5_html_generator.Testc */ SELECT testc_.Id, testc_.Other as Other0_ FROM dbo.Testc testc_ WHERE testc_.Id=@p0',N'@p0 int',@p0=103
go
exec sp_executesql N'/* insert engage5_html_generator.Testc */ INSERT INTO dbo.Testc (Other, Id) VALUES (@p0, @p1)',N'@p0 nvarchar(4000),@p1 int',@p0=N'nuevo',@p1=103
go
exec sp_executesql N'/* delete one-to-many row engage5_html_generator.Testp.Children */ UPDATE dbo.Testc SET id_p = null WHERE id_p = @p0 AND Id = @p1',N'@p0 int,@p1 int',@p0=1,@p1=1
go
exec sp_executesql N'/* delete one-to-many row engage5_html_generator.Testp.Children */ UPDATE dbo.Testc SET id_p = null WHERE id_p = @p0 AND Id = @p1',N'@p0 int,@p1 int',@p0=1,@p1=2
go
exec sp_executesql N'/* create one-to-many row engage5_html_generator.Testp.Children */ UPDATE dbo.Testc SET id_p = @p0 WHERE Id = @p1',N'@p0 int,@p1 int',@p0=1,@p1=103
go
exec sp_executesql N'/* delete engage5_html_generator.Testc */ DELETE FROM dbo.Testc WHERE Id = @p0',N'@p0 int',@p0=1
go
exec sp_executesql N'/* delete engage5_html_generator.Testc */ DELETE FROM dbo.Testc WHERE Id = @p0',N'@p0 int',@p0=2

(抱歉文字墙) 也就是说,一个选择,一个插入,三个更新和两个删除。

我期待一次删除和一次插入。

测试2:NHibernate文档说你可以通过丢弃(即解除引用)原始集合并返回一个包含所有当前元素的新实例化集合来强制它发出删除。&#34;

按原样执行test.Children = new List<Testc>();会导致异常:&#34; cascade =&#34; all-delete-orphan&#34;不再由拥有实体实例引用&#34;

将级联选项更改为All(mapping.Cascade(Cascade.All);)会稍微修复它。生成以下SQL:

exec sp_executesql N'/* load one-to-many engage5_html_generator.Testp.Children */ SELECT children0_.id_p as id3_1_, children0_.Id as Id1_, children0_.Id as Id0_0_, children0_.Other as Other0_0_, children0_.id_p as id3_0_0_ FROM dbo.Testc children0_ WHERE children0_.id_p=@p0',N'@p0 int',@p0=1
go
exec sp_executesql N'/* get current state engage5_html_generator.Testc */ SELECT testc_.Id, testc_.Other as Other0_, testc_.id_p as id3_0_ FROM dbo.Testc testc_ WHERE testc_.Id=@p0',N'@p0 int',@p0=102
go
exec sp_executesql N'/* insert engage5_html_generator.Testc */ INSERT INTO dbo.Testc (Other, id_p, Id) VALUES (@p0, @p1, @p2)',N'@p0 nvarchar(4000),@p1 int,@p2 int',@p0=N'nuevo',@p1=1,@p2=102
go
exec sp_executesql N'/* delete one-to-many engage5_html_generator.Testp.Children */ UPDATE dbo.Testc SET id_p = null WHERE id_p = @p0',N'@p0 int',@p0=1
go
exec sp_executesql N'/* create one-to-many row engage5_html_generator.Testp.Children */ UPDATE dbo.Testc SET id_p = @p0 WHERE Id = @p1',N'@p0 int,@p1 int',@p0=1,@p1=102
go

2选择,1个插入,2个更新和NO删除。这是一个软删除&#39;。

任何人都可以帮我找到一个有效的例子吗?在过去的4天里,我一直到处都试图让它发挥作用。这就是我想要的:清除集合和添加项目应该导致一次删除和许多插入。

非常感谢。

1 个答案:

答案 0 :(得分:4)

  

...即,一个选择,一个插入,三个更新和两个删除   我期待一次删除和一次插入 ......

此结果与映射有关,我们可以对其进行改进。诀窍是 inverse="true" 设置集合映射。请按照此链接获取详细信息:

如何将此设置应用于我们可以在此处观察到的代码映射:

即:

Bag(x => x.Children, mapping =>
{
    ...
    mapping.Inverse(true);

EXTEND - 一次性删除

正如评论中所讨论的,我们选择1)使用双向映射并从过度设置中获利或2)不是。但它仍然不会只是一个删除语句,因为NHibernate从不同的角度处理这些步骤然后“WRITE SQL语句的超级简化/优化”。

另一方面,NHibernate得到了扩展,为我们提供了更多的功能,进入该过程并自行完成这些“智能批量”WRITE语句。这个特征家族被称为:

一些引用:

  

这是Fabio最近移植的NHibernate的一个新功能......基本上这个功能,NHibernate现在可以在你的模型上执行基于集合的操作。这包括所有数据修改语言操作,因此我们讨论的是更新,插入和删除。

...

  

要执行HQL DELETE,请使用相同的IQuery.ExecuteUpdate()方法:

ISession session = sessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();

String hqlDelete = "delete Customer c where c.name = :oldName";
// or String hqlDelete = "delete Customer where name = :oldName";
int deletedEntities = s.CreateQuery( hqlDelete )
        .SetString( "oldName", oldName )
        .ExecuteUpdate();
tx.Commit();
session.Close();

所以,这样我们可以使用我们的1)领域模型,2)HQL和3)非常强大的批量操作......