更新孩子而不是删除它 [英] Updating child instead of deleting it
问题描述
class Person
{
int id {get;组; };
IList< PersonAddress>地址{set;得到; }
...
}
只是从地址
列表中删除一些地址,然后我真的从数据库中删除地址记录。目前这是更新地址表设置 personId = NULL ,而不是删除地址记录。有谁知道如何做到这一点。可能是一些映射问题。
这里我添加整个 Person
类映射文件。
public class PersonMappingOverride:IAutoMappingOverride< Person>
{
public void Override(AutoMapping< Person> mapping)
{
mapping.Schema(Schemas.Common);
mapping.Table(Person);
mapping.Map(x => x.FirstName).Not.Nullable();
mapping.Map(x => x.LastName).Not.Nullable();
mapping.Map(x => x.DateOfBirth).Nullable();
mapping.References(x => x.Title);
mapping.References(x => x.Ethnicity);
mapping.References(x => x.Language);
mapping.References(x => x.Religion);
mapping.References(x => x.Country);
mapping.References(x => x.Gender).Not.Nullable();
mapping.References(x => x.LoginDetail);
$ b $ map.HasMany(x => x.Addresses)
.ForeignKeyConstraintName(FK_PersonAddress_Person_PersonID)
.Where(DeletedDate is null)
.Cascade .AllDeleteOrphan()
.Cascade.SaveUpdate();
$ b mapping.HasMany(x => x.TelephoneNumbers)
.ForeignKeyConstraintName(FK_PersonTelephoneNumber_Person_PersonID)
.Where(DeletedDate is null)
.Cascade .AllDeleteOrphan()
.Cascade.SaveUpdate();
mapping.HasMany(x => x.EmailAddresses)
.ForeignKeyConstraintName(FK_PersonEmailAddress_Person_PersonID)
.Where(DeletedDate is null)
.Cascade .AllDeleteOrphan()
.Cascade.SaveUpdate();
mapping.References(x => x.Photograph);
mapping.References(x => x.Signature);
mapping.HasMany(x => x.Photographs)
.ForeignKeyConstraintName(FK_PersonPhotograph_Person_PersonID)
.Where(DeletedDate is null)
.Cascade .AllDeleteOrphan()
.Cascade.SaveUpdate();
mapping.HasMany(x => x.Signatures)
.ForeignKeyConstraintName(FK_PersonSignature_Person_PersonID)
.Where(DeletedDate is null)
.Cascade .AllDeleteOrphan()
.Cascade.SaveUpdate();
//mapping.HasMany(x => x.JobRoles)
// .ForeignKeyConstraintName(FK_PersonJobRole_Person_PersonID);
mapping.HasMany(x => x.Skills)
.ForeignKeyConstraintName(FK_PersonSkill_Person);
mapping.HasMany(x => x.SpokenLanguages)
.ForeignKeyConstraintName(FK_PersonSpokenLanguage_Person);
mapping.HasMany(x => x.ForbiddenCentres)
.ForeignKeyConstraintName(FK_PersonForbiddenCentre_Person);
mapping.HasMany(x => x.Availabilities)
.ForeignKeyConstraintName(FK_PersonAvailability_Person);
mapping.HasMany(x => x.Qualifications)
.ForeignKeyConstraintName(FK_PersonQualification_Person);
mapping.IgnoreProperty(x => x.PrimaryEmailAddress);
mapping.IgnoreProperty(x => x.WorkAddress);
$ p $这是用于 PersonAddress
mapping:
public class PersonAddressMappingOverride:IAutoMappingOverride< PersonAddress>
{
public void Override(AutoMapping< PersonAddress> mapping)
{
mapping.Schema(Schemas.Common);
mapping.Table(PersonAddress);
mapping.References(x => x.Person);
mapping.References(x => x.Address).Cascade.SaveUpdate()。Not.Nullable();
mapping.References(x => x.AddressType).Not.Nullable();
$ / code $ / pre
解决方案 em>编辑:添加下面的流利映射
我们假设您使用< bag>
看起来像这样:
< bag name =address>
< key column =PersonId/>
<一对多等级=地址/>
< / bag>
这是行得通的,并指示NHibernate维护地址$ c $收藏。如果将新对象添加到集合中,则它的 PersonId
列将更新为与当前Person关系。如果删除了某个地址,那么它的 PersonId
列将被设置为null。
如果我们需要更多,我们可以使用级联:
< bag name =addresscascade =all-delete-orphan
< key column =PersonId/>
<一对多等级=地址/>
< / bag>
在这种情况下,我们不关心关系,而是关心集合中的项目。请查看此映射以了解更多详情: 6.2。映射集合(小提取):
lockquote
cascade(可选 - 默认为none)使操作级联给子实体
现在,当我们从集合中移除地址实例时,它也将被从持久性中删除。但是,这样做的步骤是:
$ b $ ol
更新地址并设置 PersonId
为空
删除地址
:逆映射。因此,如果该地址映射到Person(多对一),我们可以使用这个映射(见 inverse =true
):
< bag name =addresscascade =all-delete-orphaninverse =true>
< key column =PersonId/>
<一对多等级=地址/>
< / bag>
哪个可以被标记为最有效的,因为所有的改变将直接在Address元素上执行(没有中间步骤)
注意:只是从6.2中引用一点:
注意:用inverse =false映射的大型NHibernate包效率低下,应该避免; NHibernate不能单独创建,删除或更新行,因为没有可用于识别单个行的密钥。
编辑:流利的映射
在这个问题中,你应该这样调整地址映射:
$ $ $ $ $ $ $ $ $ $ $映射。 > x.Addresses)
.ForeignKeyConstraintName(FK_PersonAddress_Person_PersonID)
.Where(DeletedDate is null)
.Inverse()//这将导致直接删除
.Cascade.AllDeleteOrphan()//这是应该使用的唯一级联
;
Look at the entity -
class Person
{
int id { get; set; };
IList<PersonAddress> Addresses { set; get; }
...
}
Now while updating person from UI if I just remove some addresses from the list of address then I wand to actually delete the address record from db. currently this is updating the address table setting personId = NULL and not deleting the address record. Does anyone know how to do this. may be some mapping issue.
Here I am adding whole Person
class mapping file.
public class PersonMappingOverride : IAutoMappingOverride<Person>
{
public void Override(AutoMapping<Person> mapping)
{
mapping.Schema(Schemas.Common);
mapping.Table("Person");
mapping.Map(x => x.FirstName).Not.Nullable();
mapping.Map(x => x.LastName).Not.Nullable();
mapping.Map(x => x.DateOfBirth).Nullable();
mapping.References(x => x.Title);
mapping.References(x => x.Ethnicity);
mapping.References(x => x.Language);
mapping.References(x => x.Religion);
mapping.References(x => x.Country);
mapping.References(x => x.Gender).Not.Nullable();
mapping.References(x => x.LoginDetail);
mapping.HasMany(x => x.Addresses)
.ForeignKeyConstraintName("FK_PersonAddress_Person_PersonID")
.Where("DeletedDate is null")
.Cascade.AllDeleteOrphan()
.Cascade.SaveUpdate();
mapping.HasMany(x => x.TelephoneNumbers)
.ForeignKeyConstraintName("FK_PersonTelephoneNumber_Person_PersonID")
.Where("DeletedDate is null")
.Cascade.AllDeleteOrphan()
.Cascade.SaveUpdate();
mapping.HasMany(x => x.EmailAddresses)
.ForeignKeyConstraintName("FK_PersonEmailAddress_Person_PersonID")
.Where("DeletedDate is null")
.Cascade.AllDeleteOrphan()
.Cascade.SaveUpdate();
mapping.References(x => x.Photograph);
mapping.References(x => x.Signature);
mapping.HasMany(x => x.Photographs)
.ForeignKeyConstraintName("FK_PersonPhotograph_Person_PersonID")
.Where("DeletedDate is null")
.Cascade.AllDeleteOrphan()
.Cascade.SaveUpdate();
mapping.HasMany(x => x.Signatures)
.ForeignKeyConstraintName("FK_PersonSignature_Person_PersonID")
.Where("DeletedDate is null")
.Cascade.AllDeleteOrphan()
.Cascade.SaveUpdate();
//mapping.HasMany(x => x.JobRoles)
// .ForeignKeyConstraintName("FK_PersonJobRole_Person_PersonID");
mapping.HasMany(x => x.Skills)
.ForeignKeyConstraintName("FK_PersonSkill_Person");
mapping.HasMany(x => x.SpokenLanguages)
.ForeignKeyConstraintName("FK_PersonSpokenLanguage_Person");
mapping.HasMany(x => x.ForbiddenCentres)
.ForeignKeyConstraintName("FK_PersonForbiddenCentre_Person");
mapping.HasMany(x => x.Availabilities)
.ForeignKeyConstraintName("FK_PersonAvailability_Person");
mapping.HasMany(x => x.Qualifications)
.ForeignKeyConstraintName("FK_PersonQualification_Person");
mapping.IgnoreProperty(x => x.PrimaryEmailAddress);
mapping.IgnoreProperty(x => x.WorkAddress);
}
}
This is for PersonAddress
mapping:
public class PersonAddressMappingOverride : IAutoMappingOverride<PersonAddress>
{
public void Override(AutoMapping<PersonAddress> mapping)
{
mapping.Schema(Schemas.Common);
mapping.Table("PersonAddress");
mapping.References(x => x.Person);
mapping.References(x => x.Address).Cascade.SaveUpdate().Not.Nullable();
mapping.References(x => x.AddressType).Not.Nullable();
}
}
EDIT: the fluent mapping added appended below
Let's assume your mapping using <bag>
looks like this:
<bag name="address" >
<key column="PersonId" />
<one-to-many class="Address"/>
</bag>
This is working, and instructing NHibernate to maintain address
collection. If new object is added into the collection, its PersonId
column will be updated with relationship to current Person. If some address is removed... its PersonId
column will be set to null.
If we want more, we could use cascading:
<bag name="address" cascade="all-delete-orphan"
<key column="PersonId" />
<one-to-many class="Address"/>
</bag>
In this case, we do not care only about the relationship, but even about the items inside the collection. Check this mapping for more details: 6.2. Mapping a Collection (a small extract):
(6) cascade (optional - defaults to none) enable operations to cascade to child entities
Now, when we remove the address instance from the collection, it will be also deleted from persistence. But, the steps to do that will be:
- Update address and set the
PersonId
to NULL - Delete the address
To avoid that, we can add another mapping feature: inverse mapping. So, in case, that Address has mapping to Person (many-to-one) we can use this mapping (see inverse="true"
):
<bag name="address" cascade="all-delete-orphan" inverse="true">
<key column="PersonId" />
<one-to-many class="Address"/>
</bag>
Which could be marked as the most efficient, because all the changes will be executed directly on the Address elements (no intermediate steps)
NOTE: just a small cite from the 6.2:
Note: Large NHibernate bags mapped with inverse="false" are inefficient and should be avoided; NHibernate can't create, delete or update rows individually, because there is no key that may be used to identify an individual row.
EDIT: fluent mapping
base on the mapping you've included in the question, you should adjust the Address mapping this way:
...
mapping.HasMany(x => x.Addresses)
.ForeignKeyConstraintName("FK_PersonAddress_Person_PersonID")
.Where("DeletedDate is null")
.Inverse() // this will cause the direct DELETE to be issued
.Cascade.AllDeleteOrphan() // this is the only Cascade which should be used
;
这篇关于更新孩子而不是删除它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!