Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Can't use AbpUser as navigation property] The property 'AppUser.ExtraProperties' could not be mapped #1517

Closed
holyrong opened this issue Jul 22, 2019 · 23 comments
Assignees

Comments

@holyrong
Copy link

holyrong commented Jul 22, 2019

I'm working with 0.18.1.I get the error message when add-migration.
The relation of entities like this:

image
The Entity "SchoolUsers" inherits from Entity like this:

public class  SchoolUsers : Entity
    {

        public Guid SchoolId { get; set; }
    
        public Guid UserId { get; set; }

        public virtual Users.AppUser User { get; set; }

        public virtual School School { get; set; }

        public override object[] GetKeys()
        {
            return new object[2]
            {
                SchoolId,UserId
            };
        }
    }

Config:

public override void Configure(ModelBuilder builder)
        {
            builder.Entity<Holyschool.Schools.SchoolUsers>(b =>
            {
                b.ToTable(HolyschoolConsts.DbTablePrefix + "SchoolUsers", HolyschoolConsts.DbSchema);

                b.HasKey(cs => new { cs.SchoolId, cs.UserId });

                b.HasOne(su => su.School)
                .WithMany()
                .HasForeignKey(su => su.SchoolId);

                b.HasOne(su => su.User)
                .WithMany()
                .HasForeignKey(su => su.UserId);

               // b.ConfigureFullAuditedAggregateRoot();
            });
        }
builder.Entity<AppUser>(b =>
           {
               b.ToTable("AbpUsers"); //Sharing the same table "AbpUsers" with the IdentityUser

               //b.ConfigureFullAudited();
               //b.ConfigureExtraProperties();
               //b.ConfigureConcurrencyStamp();
               b.ConfigureFullAuditedAggregateRoot();
               b.ConfigureAbpUser();

               //Moved customization to a method so we can share it with the HolyschoolMigrationsDbContext class
               b.ConfigureCustomUserProperties();
           });

when add-migration, I've received a error:

The property 'AppUser.ExtraProperties' could not be mapped, because it is of type 'Dictionary<string, object>' which is not a supported primitive type or a valid entity type. Either explicitly map this property, or ignore it using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

if replaced

b.HasOne(su => su.User)
                .WithMany()
                .HasForeignKey(su => su.UserId);

with

b.Ignore(t => t.User);
add-migration succeed, but when I execute Repository.WithDetails() in SchoolAppService, I received another error:

[Error] The property 'User' is not a navigation property of entity type 'SchoolUsers'. The 'Include(string)' method can only be used with a '.' separated list of navigation property names. System.InvalidOperationException: The property 'School' is not a navigation property of entity type 'SchoolUsers'. The 'Include(string)' method can only be used with a '.' separated list of navigation property names.

This only occured when Relation with AbpUser

I've tried #1414 ,It's not working.

@hikalkan , @maliming ,can you help me?

@yekalkan
Copy link
Member

try b.ConfigureExtraProperties();

@holyrong
Copy link
Author

try b.ConfigureExtraProperties();

The SchoolUsers is inherit from Entity, there is not any b.ConfigureExtraProperties(); for object 'b'.

I've tried b.ConfigureFullAuditedAggregateRoot(); , the error still exists.

if i delete
b.HasOne(su => su.User) .WithMany() .HasForeignKey(su => su.UserId);
and add b.Ignore(t => t.User); the error disappeared.

@gdlcf88
Copy link
Contributor

gdlcf88 commented Jul 22, 2019

Dont you have this code in your MyProjectDbContext.cs?

            builder.Entity<AppUser>(b =>
            {
                b.ToTable("AbpUsers"); //Sharing the same table "AbpUsers" with the IdentityUser
                b.ConfigureFullAuditedAggregateRoot();
                b.ConfigureAbpUser();

                //Moved customization to a method so we can share it with the MyProjectMigrationsDbContext class
                b.ConfigureCustomUserProperties();
            });

@holyrong
Copy link
Author

Dont you have this code in your MyProjectDbContext.cs?
builder.Entity(b =>
{
b.ToTable("AbpUsers"); //Sharing the same table "AbpUsers" with the IdentityUser
b.ConfigureFullAuditedAggregateRoot();
b.ConfigureAbpUser();

            //Moved customization to a method so we can share it with the MyProjectMigrationsDbContext class
            b.ConfigureCustomUserProperties();
        });

This is my code:

builder.Entity<AppUser>(b =>
            {
                b.ToTable("AbpUsers"); //Sharing the same table "AbpUsers" with the IdentityUser

                b.ConfigureFullAudited();
                b.ConfigureExtraProperties();
                b.ConfigureConcurrencyStamp();
                b.ConfigureAbpUser();

                //Moved customization to a method so we can share it with the HolyschoolMigrationsDbContext class
                b.ConfigureCustomUserProperties();
            });

@holyrong holyrong changed the title The property 'AppUser.ExtraProperties' could not be mapped [Can't use AbpUser as navigation property] The property 'AppUser.ExtraProperties' could not be mapped Jul 23, 2019
@hikalkan
Copy link
Member

hikalkan commented Aug 2, 2019

This is a common scenario. While we don't suggest to have navigation properties to other aggregate roots in DDD, it is a common habit among EF Core developers :)
We will reproduce this and will see what we can suggest.

@hikalkan
Copy link
Member

hikalkan commented Aug 2, 2019

@yekalkan can you create a new application from the startup template, create the same entities and reproduce the problem.

@yekalkan
Copy link
Member

yekalkan commented Aug 8, 2019

try this:

               if (isMigrationDbContext)
                {
                    b.Ignore(t => t.User);
                }
                else
                {
                    b.HasOne(su => su.User)
                        .WithMany()
                        .HasForeignKey(su => su.UserId);
                }

Send isMigrationDbContext as paramater from MyProjectMigrationsDbContext and MyProjectDbContext.

in MyProjectMigrationsDbContext:
image
in MyProjectDbContext:
image

@yekalkan yekalkan closed this as completed Aug 9, 2019
@hikalkan hikalkan removed this from the 0.19.0 milestone Aug 9, 2019
@tolemac
Copy link

tolemac commented Aug 13, 2019

I wrote a question about this issue on stack overflow, any help is welcome, thanks!

@wakuflair
Copy link
Contributor

Sorry I don't understand why this issue is closed, I think it has not been resolved.

@yekalkan
I tried your way, but I got only one foreign key ---- no user foreign key, but it's supposed to be two(SchoolId and UserId for the @holyrong 's sample).

Whenever an entity has relationship with AppUser(one to many, or many to many), this migration will fail with the "The property 'AppUser.ExtraProperties' could not be mapped" message.

@gdlcf88
Copy link
Contributor

gdlcf88 commented Dec 27, 2019

Sorry I don't understand why this issue is closed, I think it has not been resolved.

@yekalkan
I tried your way, but I got only one foreign key ---- no user foreign key, but it's supposed to be two(SchoolId and UserId for the @holyrong 's sample).

Whenever an entity has relationship with AppUser(one to many, or many to many), this migration will fail with the "The property 'AppUser.ExtraProperties' could not be mapped" message.

I agree with you, and this is a temporary solution I found, I hope it can help you in current situation.
https://stackoverflow.com/questions/49986756/efcore-map-2-entities-to-same-table
#1414 (comment)

@saYRam
Copy link

saYRam commented Mar 17, 2020

This is a common scenario. While we don't suggest to have navigation properties to other aggregate roots in DDD, it is a common habit among EF Core developers :)
We will reproduce this and will see what we can suggest.

is that meaning never ever use navigation properties in DDD in all conditions?

@github-ingenium
Copy link

github-ingenium commented Nov 30, 2020

I was not using ExtraProperties so below solved my issue..

public class AppUser : FullAuditedAggregateRoot<Guid>, IUser
{
// Omitted for brevity 
[NotMapped]
public override Dictionary<string, object> ExtraProperties { get; protected set; }

}

@Znow
Copy link
Contributor

Znow commented Mar 24, 2021

@github-ingenium Thanks for answer, mine came with this error:

image

so I have to used the below:

[NotMapped]
public override ExtraPropertyDictionary ExtraProperties { get; protected set; }

@ocodista
Copy link

ocodista commented Apr 8, 2021

@github-ingenium Thanks for answer, mine came with this error:

image

so I have to used the below:

[NotMapped]
public override ExtraPropertyDictionary ExtraProperties { get; protected set; }

This doesn't work for me because at the next Migration, a new table of AppUser is created.

Don't think this should be closed, there still no way to use a Navigation property of AppUser in another entity, without it, EF won't create the FK

@Znow
Copy link
Contributor

Znow commented Apr 8, 2021

@CAIOHOBORGHI

This is the solution I'm using which is working:

YourProject.Domain/SomeEntities/SomeEntity.cs

public class SomeEntity: AuditedAggregateRoot<Guid>
    {
        // OTHER PROPERTIES
        public Guid UserId { get; set; }
    }

YourProject.EntityFrameworkCore/EntityFrameworkCore/YourProjectDbContextModelCreatingExtensions.cs

builder.Entity<SomeEntity>(b =>
            {
                b.ToTable("SomeEntity", YourProjectConsts.DbSchema);
                b.ConfigureByConvention(); //auto configure for the base class props
                b.HasOne<IdentityUser>().WithMany().HasForeignKey(x => x.UserId);
            });

YourProject.EntityFrameworkCore/EntityFrameworkCore/YourProjectDbContext.cs

[ConnectionStringName("Default")]
    public class YourProjectDbContext : AbpDbContext<YourProjectDbContext>
    {
        public DbSet<AppUser> Users { get; set; }

        public DbSet<SomeEntity> SomeEntities { get; set; }

        /* Add DbSet properties for your Aggregate Roots / Entities here.
         * Also map them inside YourProjectDbContextModelCreatingExtensions.ConfigureYourProject
         */

        public YourProjectDbContext(DbContextOptions<YourProjectDbContext> options)
            : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            /* Configure the shared tables (with included modules) here */

            builder.Entity<AppUser>(b =>
            {
                b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users"); //Sharing the same table "AbpUsers" with the IdentityUser
                
                b.ConfigureByConvention();
                b.ConfigureAbpUser();
                b.ConfigureExtraProperties();

                /* Configure mappings for your additional properties
                 * Also see the YourProjectEfCoreEntityExtensionMappings class
                 */
            });

            // BUG: Below is a hack to overcome IdentityUser issues

            builder.Entity<IdentityUser>().Ignore(x => x.ExtraProperties);
            builder.Entity<IdentityUserLogin>().HasKey(x => new { x.UserId, x.LoginProvider });
            builder.Entity<IdentityUserRole>().HasKey(x => new { x.UserId, x.RoleId });
            builder.Entity<IdentityUserToken>().HasKey(x => new { x.UserId, x.LoginProvider });
            builder.Entity<IdentityUserOrganizationUnit>().HasKey(x => new { x.UserId, x.OrganizationUnitId });

            /* Configure your own tables/entities inside the ConfigureYourProject method */

            builder.ConfigureYourProject();
        }
    }

YourProject.Domain/Users/AppUser.cs

[NotMapped]
        public override ExtraPropertyDictionary ExtraProperties { get; protected set; }

@ocodista
Copy link

ocodista commented Apr 8, 2021

Thanks @Znow , with this the FK is created.

Still can't use the navigation property but it's better than no FK at all.

@ModarNa
Copy link

ModarNa commented Apr 14, 2021

I haven't tested this yet but I have used a solution based on both @Znow and @yekalkan answers

if (isMigrationDbContext)
{
    t.Ignore(x => x.AppUser); // 1st point
    t.HasOne<IdentityUser>().WithMany().HasForeignKey(x => x.AppUserId); // 2nd point
}
else
    t.HasOne(x => x.AppUser).WithMany().HasForeignKey(x => x.AppUserId); // 3rd point
  1. avoids the Can't use AbpUser as navigation property error
  2. creates the foreign key relation (without creating the AppUser table
  3. should solve the navigation property issue (not tested yet)

check @yekalkan answer to get the full picture

@Fitmavincent
Copy link

I have the same issue here while my AppUser still my aggregate root, I don't even put AppUser as Navigation property inside my entity.

builder.Entity<UserSession>(u =>
            {
                u.ToTable(
                    ProtocloudConsts.DbTablePrefix + "UserSession", 
                    ProtocloudConsts.DbSchema);

                u.HasOne<AppUser>().WithOne().HasForeignKey<AppUser>(x => x.Id);
                u.ConfigureByConvention();                
                u.Property(x => x.AutodeskUserID).IsRequired();
                u.Property(x => x.UserName).IsRequired();
                u.Property(x => x.MacID).IsRequired();
            });

Do we have an official solution for this? Or I have to do a workaround?

@johan-developer
Copy link

I have the same issue without any solution yet.

@johan-developer
Copy link

I haven't tested this yet but I have used a solution based on both @Znow and @yekalkan answers

if (isMigrationDbContext)
{
    t.Ignore(x => x.AppUser); // 1st point
    t.HasOne<IdentityUser>().WithMany().HasForeignKey(x => x.AppUserId); // 2nd point
}
else
    t.HasOne(x => x.AppUser).WithMany().HasForeignKey(x => x.AppUserId); // 3rd point
  1. avoids the Can't use AbpUser as navigation property error
  2. creates the foreign key relation (without creating the AppUser table
  3. should solve the navigation property issue (not tested yet)

check @yekalkan answer to get the full picture

I already do this and navigation property display:
Invalid object name 'AppUser'
Then not found for me.

@ghost
Copy link

ghost commented May 25, 2021

I don’t use navigation properties, just want to set a foreign key in database. I have the same issue, is there a solution?

@sukeshchand
Copy link

Is there any official solution for the issue yet?

@abu7midan
Copy link

hello

try this after entity configuration

        builder.ConfigureByConvention();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests