I have the following entity in my solution:
public class Company : FullAuditedEntity<int>
{
[Required]
[MinLength(2)]
[MaxLength(48)]
public virtual string CompanyName { get; set; }
[Required]
[MinLength(2)]
[MaxLength(48)]
public virtual string CompanyLegalName { get; set; }
[MaxLength(48)]
public virtual string CompanyTaxId { get; set; }
//some others properties removed to keep this simple
[Required]
public virtual bool ActiveYesNo { get; set; }
}
My application design keeps ALL addresses for company and any other entity in one master Address table, defined below.
public class Address : FullAuditedEntity<Int64>
{
[Required]
[MaxLength(10)]
public virtual string AddressType { get; set; }
[Required]
[MinLength(5)]
[MaxLength(100)]
public virtual string AddressLine1 { get; set; }
[Required]
[MinLength(3)]
[MaxLength(100)]
public virtual string City { get; set; }
[Required]
public virtual Country Country { get; set; }
[Required]
[MaxLength(10)]
public virtual string PostalCode { get; set; }
[Required]
public virtual bool DefaultYN { get; set; }
}
So in order to maintain the multiple addresses for the company entity, I have the table below.
public class CompanyAddress : Entity
{
public virtual Company Company { get; set; }
public virtual Address Address { get; set; }
}
Then I added this property into the company table.
public virtual CompanyAddress Addresses { get; set; }
After that, when I run the "Add-Migration" command I get this error:
Unable to determine the principal end of an association between the types 'CompanyAddress' and 'Company'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations
Then after a google search for the error, I found this post: [http://stackoverflow.com/questions/6531671/what-does-principal-end-of-an-association-means-in-11-relationship-in-entity-fr])
After reading that, I applied the below change to companyAddress table:
public class CompanyAddress : Entity
{
[Required]
public virtual Company Company { get; set; }
public virtual Address Address { get; set; }
}
This allowed me to complete the "Add-Migration" command without any errors.
Here is the code for the migration:
public override void Up()
{
DropIndex("dbo.app_CompanyAddress", new[] { "Company_Id" });
DropColumn("dbo.app_CompanyAddress", "Id");
RenameColumn(table: "dbo.app_CompanyAddress", name: "Company_Id", newName: "Id");
DropPrimaryKey("dbo.app_CompanyAddress");
AlterColumn("dbo.app_CompanyAddress", "Id", c => c.Int(nullable: false));
AlterColumn("dbo.app_CompanyAddress", "Id", c => c.Int(nullable: false));
AddPrimaryKey("dbo.app_CompanyAddress", "Id");
CreateIndex("dbo.app_CompanyAddress", "Id");
}
public override void Down()
{
DropIndex("dbo.app_CompanyAddress", new[] { "Id" });
DropPrimaryKey("dbo.app_CompanyAddress");
AlterColumn("dbo.app_CompanyAddress", "Id", c => c.Int());
AlterColumn("dbo.app_CompanyAddress", "Id", c => c.Int(nullable: false, identity: true));
AddPrimaryKey("dbo.app_CompanyAddress", "Id");
RenameColumn(table: "dbo.app_CompanyAddress", name: "Id", newName: "Company_Id");
AddColumn("dbo.app_CompanyAddress", "Id", c => c.Int(nullable: false, identity: true));
CreateIndex("dbo.app_CompanyAddress", "Company_Id");
}
However, when I apply the "Update-Database" command, I get the following error:
The object 'PK_dbo.app_CompanyAddress' is dependent on column 'Id'.
ALTER TABLE DROP COLUMN Id failed because one or more objects access this column.
Can you please tell me what I am doing wrong or what I am missing in order to setup this relationship properly? Thanks!
11 Answer(s)
-
0
Hi,
Can you try to add CompanyId and AddressId to CompanyAddress entity as well ?
-
0
-
0
By adding the below changes, I was able to make the relationship work. I also did not have to add another migration for this change.
public virtual List<CompanyAddress> Addresses { get; set; } public virtual List<CompanyContact> Contacts { get; set; } public Company() { Addresses = new List<CompanyAddress>(); Contacts = new List<CompanyContact>(); }
I made the above code change after reading this article: [http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx])
-
0
Now I have new issue related to this relationship setup.
When the company app service method "GetCompanyForEdit" is called, it returns all the company data plus the addresses and contacts for the selected company. But when the method executes the MapTo<> statement, an exception is thrown.
This file shows all the code and the error message: [https://drive.google.com/open?id=0BzbrPy41GhA4TmoxNnJIeV9IMFk])
-
0
Hi,
You need to use AutoMap attribute instead of AutoMapTo I think. Probably you will use those entities both for displaying edit data and saving the edited data.
-
0
Can you be more specific on which ones i need to add this to?
I added it to EditContactDto, EditAddressDto and EditCompanyDto. After that I still get the same kind of error, see below.
AutoMapper.AutoMapperMappingException: Error mapping types. Mapping types: Company -> EditCompanyDto NursingOps.Company -> NursingOps.Dto.EditCompanyDto Type Map configuration: Company -> EditCompanyDto NursingOps.Company -> NursingOps.Dto.EditCompanyDto Property: Contacts ---> AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping. Mapping types: CompanyContact -> EditContactDto NursingOps.CompanyContact -> NursingOps.Dto.EditContactDto at lambda_method(Closure , CompanyContact , EditContactDto , ResolutionContext ) at AutoMapper.ResolutionContext.Map[TSource,TDestination](TSource source, TDestination destination) at lambda_method(Closure , Object , Object , ResolutionContext ) --- End of inner exception stack trace --- at lambda_method(Closure , Object , Object , ResolutionContext ) at AutoMapper.Mapper.AutoMapper.IMapper.Map[TDestination](Object source) at AutoMapper.Mapper.Map[TDestination](Object source) at Abp.AutoMapper.AutoMapExtensions.MapTo[TDestination](Object source) in D:\Halil\GitHub\aspnetboilerplate\src\Abp.AutoMapper\AutoMapper\AutoMapExtensions.cs:line 15 at NursingOps.CompanyAppService.d__9.MoveNext() in Application\NursingOps\CompanyAppService.cs:line 79 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.Threading.InternalAsyncHelper.d__5`1.MoveNext() in D:\Halil\GitHub\aspnetboilerplate\src\Abp\Threading\InternalAsyncHelper.cs:line 120 --- End of stack...
-
0
Hi,
The error message says, it is because of EditContactDto class. If you added [AutoMap(Contact)] attribute on it, then the problem is probably because of it's Id type. Your Contact entity is FullAuditedEntity<Int64> but EditContactDto is EntityDto. You should change it to EntityDto<Int64> as well.
Please write back if this does not solve the problem.
-
0
I tried your idea, and set the PK to "long" (Int64) on the DTO and Entity. Still I get the same error?
AutoMapper.AutoMapperMappingException: Error mapping types. Mapping types: Company -> EditCompanyDto NursingOps.Company -> NursingOps.Dto.EditCompanyDto Type Map configuration: Company -> EditCompanyDto NursingOps.Company -> NursingOps.Dto.EditCompanyDto Property: Contacts ---> AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping. Mapping types: CompanyContact -> EditContactDto NursingOps.CompanyContact -> NursingOps.Dto.EditContactDto at lambda_method(Closure , CompanyContact , EditContactDto , ResolutionContext ) at AutoMapper.ResolutionContext.Map[TSource,TDestination](TSource source, TDestination destination) at lambda_method(Closure , Object , Object , ResolutionContext ) --- End of inner exception stack trace --- at lambda_method(Closure , Object , Object , ResolutionContext ) at AutoMapper.Mapper.AutoMapper.IMapper.Map[TDestination](Object source) at AutoMapper.Mapper.Map[TDestination](Object source) at Abp.AutoMapper.AutoMapExtensions.MapTo[TDestination](Object source) in D:\Halil\GitHub\aspnetboilerplate\src\Abp.AutoMapper\AutoMapper\AutoMapExtensions.cs:line 15 at NursingOps.CompanyAppService.d__9.MoveNext() in \Application\NursingOps\CompanyAppService.cs:line 79 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.Threading.InternalAsyncHelper.d__5`1.MoveNext() in D:\Halil\GitHub\aspnetboilerplate\src\Abp\Threading\InternalAsyncHelper.cs:line 120 --- End of stack...
-
0
Hi,
You have lost a lot of time I think because of this. Can you send your project to us <a href="mailto:[email protected]">[email protected]</a>.
It will be easier to find out the problem in Visual Studio.
-
0
Thanks!
I have emailed you solution for review.
-
0
I replied to your latest email and I made some more updates to the DTO classes based on your email.
Can you check the updated code and respond to my latest email? I am very much at a standstill due to this issue.
Thanks!