问题
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();
}
}
回答1:
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
;
来源:https://stackoverflow.com/questions/20755311/updating-child-instead-of-deleting-it