Base solution for your next web application
Starts in:
01 DAYS
01 HRS
01 MIN
01 SEC
Open Closed

EF One to many relationship error - need help #2173


User avatar
0
exlnt created

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)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Can you try to add CompanyId and AddressId to CompanyAddress entity as well ?

  • User Avatar
    0
    exlnt created

    They are already in my table, see below.

    [attachment=0:13vf8zqo]Screenshot (42).png[/attachment:13vf8zqo]

  • User Avatar
    0
    exlnt created

    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])

  • User Avatar
    0
    exlnt created

    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])

  • User Avatar
    0
    ismcagdas created
    Support Team

    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.

  • User Avatar
    0
    exlnt created

    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...
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    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.

  • User Avatar
    0
    exlnt created

    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...
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    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.

  • User Avatar
    0
    exlnt created

    Thanks!

    I have emailed you solution for review.

  • User Avatar
    0
    exlnt created

    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!