我们有Bar和Foo类,他们有一个简单的多对多关系:
public partial class Bar
{
public virtual Guid BarId { get; set; } = Guid.Empty;
public virtual IList<Foo> ManyBarsInManyFoos { get; protected set; } = new Collection<Foo>();
}
public partial class Foo
{
public virtual Guid FooId { get; set; } = Guid.Empty;
public virtual IList<Bar> ManyFoosInManyBars { get; protected set; } = new Collection<Bar>();
}
一开始,我用bag来映射多对多:
<class name="Bar" table="Bars" optimistic-lock="version">
<id name="BarId" unsaved-value="{00000000-0000-0000-0000-000000000000}">
<generator class="guid" />
</id>
<timestamp name="LastChange" />
<bag name="ManyBarsInManyFoos" table="ManyBarsInManyFoos" cascade="save-update" inverse="false">
<key column="ManyBarsInManyFoosBarId" />
<many-to-many column="ManyFoosInManyBarsFooId" class="Many2Many.DomainModel.Foo" />
</bag>
</class>
<class name="Foo" table="Foos" optimistic-lock="version">
<id name="FooId" unsaved-value="{00000000-0000-0000-0000-000000000000}">
<generator class="guid" />
</id>
<timestamp name="LastChange" />
<bag name="ManyFoosInManyBars" table="ManyBarsInManyFoos" cascade="save-update" inverse="false">
<key column="ManyFoosInManyBarsFooId" />
<many-to-many column="ManyBarsInManyFoosBarId" class="Many2Many.DomainModel.Bar" />
</bag>
</class>
这很好,但我们发现当删除单个关联(ManyBarsInManyFoos表中的一行)时,NHibernate会删除与该BarId相关的所有行,然后重新插入其他行:
'UPDATE dbo.Bars SET LastChange = @p0 WHERE BarId = @p1 AND LastChange = @p2',N'@p0 datetime,@p1 uniqueidentifier,@p2 datetime',@p0='2018-05-22 17:22:17.760',@p1='F111C29E-41C1-483F-AC28-053A53713A10',@p2='2018-05-22 17:21:44.410'
'UPDATE dbo.Foos SET LastChange = @p0 WHERE FooId = @p1 AND LastChange = @p2',N'@p0 datetime,@p1 uniqueidentifier,@p2 datetime',@p0='2018-05-22 17:22:17.760',@p1='5204C39B-265F-47F7-AA30-2D104A6FCEFB',@p2='2018-05-22 17:21:44.440'
'DELETE FROM dbo.ManyBarsInManyFoos WHERE ManyBarsInManyFoosBarId = @p0',N'@p0 uniqueidentifier',@p0='F111C29E-41C1-483F-AC28-053A53713A10'
'INSERT INTO dbo.ManyBarsInManyFoos (ManyBarsInManyFoosBarId, ManyFoosInManyBarsFooId) VALUES (@p0, @p1)',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='F111C29E-41C1-483F-AC28-053A53713A10',@p1='D1A635A0-360D-4AC1-98EE-EE3CE47BE63C'
'INSERT INTO dbo.ManyBarsInManyFoos (ManyBarsInManyFoosBarId, ManyFoosInManyBarsFooId) VALUES (@p0, @p1)',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='F111C29E-41C1-483F-AC28-053A53713A10',@p1='58EA2B80-C8D9-4708-90D7-FA110816715B'
'DELETE FROM dbo.ManyBarsInManyFoos WHERE ManyFoosInManyBarsFooId = @p0',N'@p0 uniqueidentifier',@p0='5204C39B-265F-47F7-AA30-2D104A6FCEFB'
'INSERT INTO dbo.ManyBarsInManyFoos (ManyFoosInManyBarsFooId, ManyBarsInManyFoosBarId) VALUES (@p0, @p1)',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='5204C39B-265F-47F7-AA30-2D104A6FCEFB',@p1='B67DE063-BFD9-4AE3-BADA-2B3B5669295D'
'INSERT INTO dbo.ManyBarsInManyFoos (ManyFoosInManyBarsFooId, ManyBarsInManyFoosBarId) VALUES (@p0, @p1)',N'@p0 uniqueidentifier,@p1 uniqueidentifier',@p0='5204C39B-265F-47F7-AA30-2D104A6FCEFB',@p1='0DB243BC-3C89-43E0-AD55-C0CD8120E711'
似乎需要这种行为来处理包中相同对象之间的多个关系,而不是索引。 但是我们需要(由于触发器或类似的东西),ManyBarsInManyFoos表中现有的多对多行不会被删除(除了与删除的关系真正相关的行)。
第一个问题:有没有办法避免这种“大规模”删除并告诉NHibernate只删除涉及的行?
认为这可能是不可能的,我尝试使用 list 而不是 bag :
<list name="ManyBarsInManyFoos" table="ManyBarsInManyFoos" cascade="save-update">
<key column="ManyBarsInManyFoosBarId" />
<index column="Position"/>
<many-to-many column="ManyFoosInManyBarsFooId" class="Many2Many.DomainModel.Foo" />
</list>
-------
<list name="ManyFoosInManyBars" table="ManyBarsInManyFoos" cascade="save-update" inverse="true">
<key column="ManyFoosInManyBarsFooId" />
<index column="Position"/>
<many-to-many column="ManyBarsInManyFoosBarId" class="Many2Many.DomainModel.Bar" />
</list>
但是在删除现有关联时,事情变得有些奇怪(对我而言):
'UPDATE dbo.Bars SET LastChange = @p0 WHERE BarId = @p1 AND LastChange = @p2',N'@p0 datetime,@p1 uniqueidentifier,@p2 datetime',@p0='2018-05-22 17:56:46.480',@p1='301E92EA-5E37-4948-A0FE-00884D5EB221',@p2='2018-05-22 17:56:32.180'
'DELETE FROM dbo.ManyBarsInManyFoos WHERE ManyBarsInManyFoosBarId = @p0 AND Position = @p1',N'@p0 uniqueidentifier,@p1 int',@p0='301E92EA-5E37-4948-A0FE-00884D5EB221',@p1=2
'UPDATE dbo.ManyBarsInManyFoos SET ManyFoosInManyBarsFooId = @p0 WHERE ManyBarsInManyFoosBarId = @p1 AND Position = @p2',N'@p0 uniqueidentifier,@p1 uniqueidentifier,@p2 int',@p0='CE0C01A3-4F0E-4E93-A33C-22AAE68482D9',@p1='301E92EA-5E37-4948-A0FE-00884D5EB221',@p2=0
'UPDATE dbo.ManyBarsInManyFoos SET ManyFoosInManyBarsFooId = @p0 WHERE ManyBarsInManyFoosBarId = @p1 AND Position = @p2',N'@p0 uniqueidentifier,@p1 uniqueidentifier,@p2 int',@p0='193C5714-FD1C-4C51-AD5F-6B19F262046F',@p1='301E92EA-5E37-4948-A0FE-00884D5EB221',@p2=1
其他行不会被删除,但可能会在幕后从对象“切换”到另一行。不是有效的解决方案。
最后,我尝试使用 map ...尝试过,但我无法理解如何为这种简单的关系创建正确的映射标记。
因此,第二个问题:如何使用 map 标记映射多对多?和/或我们如何以优化的方式映射这种多对多关系,让NHibernate简单地删除ManyBarsInManyFoos表中的单个涉及的行,而不是删除许多行以在一段时间后重新插入那些或“重新分配”关系行不同的对象?