abpframework / abp

Open Source Web Application Framework for ASP.NET Core. Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET and the ASP.NET Core platforms. Provides the fundamental infrastructure, production-ready startup templates, application modules, UI themes, tooling, guides and documentation.
https://abp.io
GNU Lesser General Public License v3.0
12.31k stars 3.32k forks source link

Owned Entities and Identity User #2857

Closed newacc12 closed 4 years ago

newacc12 commented 4 years ago

When I try to add a Value Object as a owned entity on the AppUser class I get the following error:

The navigation property 'Prop1' cannot be added to the entity type 'IdentityUser' because there is no corresponding CLR property on the underlying type and navigations properties cannot be added to shadow state.

I've seen similar error messages in other posts but no solutions. I've tried using a brand new regular MVC project without ABP works perfectly. I can easily create a AppUser class, a VO class and configure as an owned entity and it just works. I also tried adding builder.Owned(); before base.OnModelCreating(builder); but it didn't change anything.

Is anyone else having this problem or it is just me?

maliming commented 4 years ago

hi @newacc12

Owned Entity has some restrictions, please share your entity code and EF configuration code.

newacc12 commented 4 years ago

TestVo.cs

public class TestVo
    {
        public string Prop1 { get; }
        public string Prop2 { get; }

        public TestVo(string prop1, string prop2)
        {
            Prop1 = prop1;
            Prop2 = prop2;
        }
    }

ABP CODE AppUser.cs

 public virtual TestVo Test { get; set; }

DbContextModelCreatingExtensions.cs

public static void ConfigureCustomUserProperties<TUser>(this EntityTypeBuilder<TUser> b)
            where TUser: class, IUser
        {

            b.OwnsOne(typeof(TestVo), nameof(AppUser.Test));
            b.Property<string>(nameof(AppUser.Test));
        }

Running a update-database with the code above shows: The navigation property 'Test' cannot be added to the entity type 'IdentityUser' because there is no corresponding CLR property on the underlying type and navigations properties cannot be added to shadow state.

Now using a plain .NET Core 3.1 Web Project with the same TestVo class with the only difference being the configuration on the DBContext class it works:

builder.Entity<MyUser>().OwnsOne(p => p.Test);

Let me know if that is sufficient. If not, I will recreate the entire example again and upload on github.

maliming commented 4 years ago

This is like the limitation of abp shared table.

Follow: https://github.com/abpframework/abp/issues/2278

newacc12 commented 4 years ago

Hmm... #2278 states that Inheritance hierarchies that include owned entity types are not supported but I am not using any inheritance on my VO type. This link also states that it should work.

Is ABP doing something special behind the scenes or maybe is there a workaround for now?

maliming commented 4 years ago

Is ABP doing something special behind the scenes

Because abp is using shared table(AppUser and IdentityUser).

The limit of ef is navigations properties cannot be added to shadow state.

newacc12 commented 4 years ago

Hmm not sure what you mean by 'shared table'. I created a brand new web MVC project and I am using AppUser and IdentityUser and it just works: https://github.com/newacc12/TestOwnedTypes

Trying to the exact the same with ABP doesn't work. Maybe there is a work around for now?

maliming commented 4 years ago

shared table

https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Migrations#reusing-a-table-of-a-module

newacc12 commented 4 years ago

@maliming I read the docs but couldn't find a reason why this wouldn't work. So I assume this is a limitation of ABP instead of EF since the example that I posted works. In that case are there any plans to look into it?

maliming commented 4 years ago

This is a limitation of the ABP shared table, and of course also related to ef core.

The documentation provides a way to Alternative Approaches.

hikalkan commented 4 years ago

I suppose you all understood the problem. This is not a restriction of the ABP framework. You are adding a nagivation property to a shared table (AbpUsers table is shared between AppUser (your entity) and IdentityUser (identity module's entity)) and EF normally doesn't support such a usage. The migration document explains an approach overcome this problem, but it can not solve all the problems.

A workaround can be this: Just add Prop1 and Prop2 as normal string properties inside the ConfigureCustomUserProperties method. This will just make this fields added to the table. MigrationDbContext is only used for database migration, so no problem. On runtime, your main dbcontext is used and you can configure the TestVo as normal owned entity inside your dbcontext (right here)

gdlcf88 commented 4 years ago

To me, if I start a new abp solution, I will delete the AppUser and create a new aggregate root UserInfo. 🉑

hikalkan commented 4 years ago

What's the difference between AppUser and UserInfo except their names?

gdlcf88 commented 4 years ago

When I use AppUser with relationships (like AppUserInfo entity), I have some problems. https://github.com/abpframework/abp/issues/1414

UserInfo does not use shared table. Most of the time I will use IdentityUser directly, when I need some details, I can load UserInfo aggregate root from its repository.

newacc12 commented 4 years ago

@hikalkan Thanks for the reply. Did you have a chance to look at the code that I posted here: https://github.com/newacc12/TestOwnedTypes ?

So, in ABP:

The code that I posted:

Does that look right? If it does why Address would work when being configure like this.

What am I missing?

EDIT: NVM, I think I got it what you mean by shared table. It looks like my example is not the same as ABP. I tried your work around and it seems to work. I will play a little bit more with it. Thanks for your patience and @maliming !

gdlcf88 commented 4 years ago

Another problem: sometimes I cannot change both IdentityUser and AppUser in the same uow.

hikalkan commented 4 years ago

Another problem: sometimes I cannot change both IdentityUser and AppUser in the same uow.

That's expected. Use different UOWs (manage UOW manually).

gdlcf88 commented 4 years ago

Another problem: sometimes I cannot change both IdentityUser and AppUser in the same uow.

That's expected. Use different UOWs (manage UOW manually).

Maybe I need to grant roles to IdentityUser, and then set AppUser.IsAuthorized = true. (if the latter fails, the former needs to be rolled back)

In general, shared table bings more troubles.

newacc12 commented 4 years ago

Another problem: sometimes I cannot change both IdentityUser and AppUser in the same uow.

That's expected. Use different UOWs (manage UOW manually).

Maybe I need to grant roles to IdentityUser, and then set AppUser.IsAuthorized = true. (if the latter fails, the former needs to be rolled back)

In general, shared table bings more troubles.

Damn, I wouldn't like that. So, please bear with me as I am pretty new to ABP, the purpose of extending IdentityUser is so I can customize the user in my app (add more information and/or relationships), right? Do you mean that if I start using AppUser through my app I still have to deal with IdentityUser? Would I be able to extend the existing stores so all the code would be working with AppUser instead of IdentityUser? I am pretty sure I was able to do that with the previous version of ABP (before .NET Core)

gdlcf88 commented 4 years ago

Yes, IdentityUserManager providers some important methods, for example, setting user's email, granting roles.

newacc12 commented 4 years ago

but can it be extended to work with AppUsers instead? If so, wouldn't the problem that you describe go away?

gdlcf88 commented 4 years ago

I don't know if it can be realized, or maybe it has been realized, but I just don't know the usage.