dcpartners
dcpartners

Reputation: 5456

Issue on add-migration in this current bridging class (many-to-many)

Currently, we have this model - HostApplicationUser and it's bridging for Many-To-Many relationship between Host and ApplicationUser (extended from IdentityUser).

public class HostApplicationUser
{
    public Guid HostID { get; set; }

    public Host Host { get; set; }

    public string Id { get; set; }

    public ApplicationUser ApplicationUser { get; set; }

    public bool IsDeleted { get; set; }

    [Timestamp]
    public byte[] RowVersion { get; set; }

}

An in our, ApplicationDBContext we modified the protected override void OnModelCreating(ModelBuilder builder) to include as follow:

// Many to Many relationships

            builder.Entity<HostApplicationUser>()
                .HasKey(bc => new { bc.HostID, bc.Id });


            builder.Entity<HostApplicationUser>()
                .HasOne(bc => bc.Host)
                .WithMany(b => b.HostApplicationUsers)
                .HasForeignKey(bc => bc.HostID);

            builder.Entity<HostApplicationUser>()
                .HasOne(bc => bc.ApplicationUser)
                .WithMany(c => c.HostApplicationUsers)
                .HasForeignKey(bc => bc.Id);

This code has been running ok. BUT now we have a new requirement to add few properties/navigation as follow:

public class HostApplicationUser
{
    public Guid HostID { get; set; }

    public Host Host { get; set; }

    public string Id { get; set; }

    public ApplicationUser ApplicationUser { get; set; }

    public DateTime CreatedUTC { get; set; }

    public string CreatedBy { get; set; }

    public DateTime LastModifiedUTC { get; set; }

    public string LastModifiedBy { get; set; }

    public DateTime? DeletedUTC { get; set; }

    public string DeletedBy { get; set; }

    public bool IsDeleted { get; set; }

    [Timestamp]
    public byte[] RowVersion { get; set; }

    [ForeignKey("CreatedBy")]
    public ApplicationUser ApplicationCreatedUser { get; set; }

    [ForeignKey("LastModifiedBy")]
    public ApplicationUser ApplicationLastModifiedUser { get; set; }

}

Then we have an error when we run the add-migration:

Unable to determine the relationship represented by navigation property 'HostApplicationUser.ApplicationCreatedUser' of type 'ApplicationUser'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

Any ideas on how to adjust fix this? I believe this something to do with OnModelCreating(ModelBuilder builder) to include the other navigation but not sure how to do that.

Thanks

Upvotes: 1

Views: 67

Answers (1)

itminus
itminus

Reputation: 25380

The reason

The reason is that there're multiple navigation properties on the dependent and principal entities pairs. Considering the following relationships between HostApplicationUser and ApplicationUser :

  1. ApplicationUser <-> HostApplicationUser.ApplicationUser
  2. ApplicationUser <-> HostApplicationUser.ApplicationCreatedUser
  3. ApplicationUser <-> HostApplicationUser.ApplicationLastModifiedUser
  4. ... and a potential relationship for DeletedBy

If you have an navigation property to HostApplicationUser on ApplicationUser :

public class ApplicationUser{
    public string Id{get;set;}
    public string Name {get;set;}

    public IList<HostApplicationUser> HostApplicationUsers{get;set;} 
}

And if there's no extra configuration , the EF Core cannot determine whether the Application.HostApplicationUsers property is CreatedUsers , LastModifiedUsers, DeletedUsers or something other users, i.e., the EF Core cannot determine how the ApplicationUser.HostApplicationUsers property is navigated to HostApplicationUser, thus complains :

Unable to determine the relationship represented by navigation property 'HostApplicationUser.ApplicationCreatedUser' of type 'ApplicationUser'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

How to fix

To fix the issue, simply decorate the ApplicationUser.HostApplicationUsers with an InversePropertyAttribute :

public class ApplicationUser{
    public string Id{get;set;}
    public string Name {get;set;}

    [InverseProperty("ApplicationUser")]
    public IList<HostApplicationUser> HostApplicationUsers{get;set;} 
}

Or if would like to have multiple navigation properties, you need to add [InverseProperty("ApplicationCreatedUser")],[InverseProperty("ApplicationLastModifiedUser")],[InverseProperty("ApplicationDeletedUser")] and so on for each navigation property :

public class ApplicationUser{
    public string Id{get;set;}
    public string Name {get;set;}

    [InverseProperty("ApplicationUser")]
    public IList<HostApplicationUser> HostApplicationUsers{get;set;} 

    [InverseProperty("ApplicationCreatedUser")]
    public IList<HostApplicationUser> HostApplicationCreatedUsers{get;set;}

    [InverseProperty("ApplicationLastModifiedUser")]
    public IList<HostApplicationUser> HostApplicationLastModifiedUsers{get;set;}

    // ...
}

Upvotes: 2

Related Questions