How do I map table inheritance in a legacy database?
I am finding it very difficult to map a legacy database.
Here is the scenario: A contractor applies for a new license. The license is queried and displayed. The contractor modifies any information that needs to be modified. And upon completion an application is saved to the database.
A license belongs to either a business or an owner, this is a one to any polymorphic association. T开发者_如何学运维he License itself holds a TableID and RecordID that are used to make the association.
Licenses have many Applications. There are several types of Applications in this System, so there is an "ApplicationCommon" table and an "LicenseApplication" table. This particular application is a for a license. The ApplicationCommon and The LicenseApplication share the same primary key. In other words the ApplicationCommon id is the same and the LicenseApplication id. So this is table inheritance (or so I think).
Because of the weird polymorphic association with the business, I have to query for the business data separately from the license (Or so I think, kind of new to nHibernate). Once I have the license and the business I try to make a new application, that is when the system fails.
Here is the exception that I get:
"object references an unsaved transient instance - save the transient instance
before flushing. Type: LicenseApplication, Entity: LicenseApplication"
Here are the mappings:
public LicenseApplicationMap()
{
Table("Applications_LicenseApplication");
Id(x => x.ID).Column("intApplicationID").Not.Nullable();
Map(x => x.TableID).Column("intTableID").Nullable();
Map(x => x.RecordID).Column("intRecordID").Nullable();
References(x => x.Type).Column("intLicenseTypeID").Not.Nullable();
Map(x => x.InsuranceExpiresOn).Column("dtInsuranceExpiresOn");
Map(x => x.WCInsuranceExpiresOn).Column("dtWCInsuranceExpiresOn");
Map(x => x.Updated).Column("dtUpdated");
Map(x => x.AuthorizedRepresentativeFirstName).Column("strAuthRepFirstName");
Map(x => x.AuthorizedRepresentativeLastName).Column("strAuthRepLastName");
Map(x => x.AuthorizedRepresentativeGreeting).Column("strAuthRepGreeting");
HasOne(x => x.ApplicationCommon).ForeignKey("intApplicationID").Cascade.All();
References(x => x.License).Column("intLicenseID");
HasMany(x => x.Officers).KeyColumn("intApplicationID");
HasMany(x => x.Designees).KeyColumn("intApplicationID");
}
.
public LicenseCommonMap()
{
Table("Licensing_LicenseCommon");
Id(x => x.ID).Column("intLicenseID").Not.Nullable();
Map(x => x.TableID).Column("intTableID").Nullable();
Map(x => x.RecordID).Column("intRecordID").Nullable();
Map(x => x.LicenseNumber).Column("strNumber");
References(x => x.Type).Column("intLicenseTypeID").Not.Nullable();
References(x => x.Status).Column("intLicenseStatusID").Not.Nullable();
Map(x => x.StartsOn).Column("dtStartsOn");
Map(x => x.EndsOn).Column("dtEndsOn");
Map(x => x.CreatedOn).Column("dtCreatedOn");
Map(x => x.RenewedOn).Column("dtRenewedOn");
Map(x => x.InsuranceExpiresOn).Column("dtInsuranceExpiresOn");
Map(x => x.WorkmansCompensationExpiresOn).Column("dtWCInsuranceExpiresOn");
Map(x => x.LastUpdated).Column("dtLastUpdated");
HasMany(x => x.Applications).KeyColumn("intLicenseID");
}
.
public ApplicationCommonMap()
{
Table("Applications_ApplicationCommon");
Id(x => x.ID).Column("intApplicationID");
References(x => x.Type).Column("intApplicationTypeID");
References(x => x.Status).Column("intApplicationStatusID");
References(x => x.LicenseApplication).Column("intApplicationID").Cascade.All();
}
.
public BusinessMap()
{
Table("Core_Business");
Id(x => x.ID).Column("intBusinessID").GeneratedBy.Identity();
Map(x => x.BusinessName).Column("strBusinessName").Not.Nullable();
Map(x => x.PhoneNumber).Column("strPhoneNumber").Not.Nullable();
Map(x => x.FaxNumber).Column("strFaxNumber").Not.Nullable();
Map(x => x.EmailAddress).Column("strEmailAddress").Not.Nullable();
Map(x => x.YearOrganized).Column("strYearOrganized").Not.Nullable();
Map(x => x.LastUpdated).Column("dtLastUpdated").Not.Nullable();
Map(x => x.PhysicalAddr1).Column("strPhysicalAddr1").Not.Nullable();
Map(x => x.PhysicalAddr2).Column("strPhysicalAddr2").Nullable();
Map(x => x.PhysicalCity).Column("strPhysicalCity").Not.Nullable();
Map(x => x.PhysicalState).Column("strPhysicalState").Not.Nullable();
Map(x => x.PhysicalCountry).Column("strPhysicalCountry").Not.Nullable();
Map(x => x.PhysicalZip).Column("strPhysicalZip").Not.Nullable();
Map(x => x.MailingAddr1).Column("strMailingAddr1").Not.Nullable();
Map(x => x.MailingAddr2).Column("strMailingAddr2").Nullable();
Map(x => x.MailingCity).Column("strMailingCity").Not.Nullable();
Map(x => x.MailingState).Column("strMailingState").Not.Nullable();
Map(x => x.MailingCountry).Column("strMailingCountry").Not.Nullable();
Map(x => x.MailingZip).Column("strMailingZip").Not.Nullable();
}
And finally, I am using .Net MVC, AutoMapper and S#rpArch, so here is my controller action, and my query. SaveLicense and SaveQuery bother perform the same logic, SaveOrUpdate, then Flush.
[HttpPost]
[Transaction]
public ActionResult Edit(int id, LicenseViewModel applicationData)
{
// 1. Get the current license.
var license = _licenseService.GetLicenseCommon(id);
// 2. Make changes to license that where made during application process
Mapper.Map<LicenseViewModel , LicenseCommon>(applicationData, license);
var business = _licenseService.GetBusiness(license.RecordID);
Mapper.Map<LicenseViewModel , Business>(applicationData, business);
business.LastUpdated = DateTime.Now;
// 3. Create a new application and add it to the license
var application = new LicenseApplication();
Mapper.Map<LicenseViewModel , LicenseApplication>(applicationData, application);
application.Updated = DateTime.Now;
application.InsuranceExpiresOn = DateTime.Parse(applicationData.GeneralLiabilityExpiration);
application.WCInsuranceExpiresOn = DateTime.Parse(applicationData.WorkmansCompensationExpiration);
application.TableID = 33;
application.RecordID = license.RecordID;
// 4. Save the license and it's applications to the database.
license.Business = business; //Don't think this works at all...
license.Applications.Add(application);
application.License = license;
///////////////// BOOM THIS IS WHERE IT BLOWS UP //////////////////////
_licenseService.SaveLicense(license);
_businessService.SaveBusiness(business);
// 5. Convert the modified license and it's newly created application to an LicenseViewModel
Mapper.Map<LicenseCommon, LicenseViewModel >(license, applicationData);
// 6. return json or error message
return Json(applicationData);
}
Please tell me what is wrong with my mappings.
HasMany(x => x.Applications).KeyColumn("intLicenseID");
is missing a .Cascade.All()
so saving the license also saves changes to Applications.
And .Inverse
would be good too to tell NH that Application is responsible for the association.
And also
// class LicenseCommon
public void Add(LicenseApplication application)
{
application.License = license;
application.TableID = 33;
application.RecordID = license.RecordID;
Applications.Add(application);
}
精彩评论