Closed XuJin186 closed 4 years ago
Can you use cli to create a project to reproduce the problem?
@maliming Demo.zip
The main problem is that I use the FullAuditedEntityWithUser <Guid, IdentityUser> class. If I use IdentityUser, it can be migrated, but it will report an error when running, if I use Appuser, it will run normally, but it will be abnormal during migration.
What are the steps?
Add Test
entity in Demo.Domain
public class Test : FullAuditedEntityWithUser<Guid, IdentityUser> { public string Name { get; set; } }
I used the FullAuditedEntityWithUser base class
Then I wrote the ConfigureDemo method in OnModelCreating
public static void ConfigureDemo(this ModelBuilder builder) { Check.NotNull(builder, nameof(builder)); builder.Entity<Test>(b => { b.ToTable("Tests"); b.Property(nameof(Test.Name)).IsRequired(false).HasMaxLength(200); b.ConfigureFullAudited(); }); } }
Then perform the migration, everything is normal
Then execute the GetListAsync method in the TestApplicationService in the Demo.Application project, you will get an error message
The entity type 'IdentityUserLogin' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'. System.InvalidOperationException: The entity type 'IdentityUserLogin' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'.
@maliming If I change FullAuditedEntityWithUser <Guid, IdentityUser> to FullAuditedEntityWithUser <Guid, AppUser>, it works fine, but adding the migration again after changing the entity properties will be abnormal
Then perform the migration, everything is normal Then execute the GetListAsync method in the TestApplicationService in the Demo.Application project, you will get an error message
I can't reproduce it.
@maliming
You can open the demo project that I uploaded. It has been written and reproduced. You can update-databse directly, and then run GetListAsync in the Test service
Hi @maliming , I can reproduce this issue.
PM> update-database
Build started...
Build succeeded.
System.InvalidOperationException: 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'.
at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidatePropertyMapping(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger
1 logger)
at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger
1 logger)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext1 context) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IConventionModelBuilder modelBuilder) at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel() at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel() at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder) at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor
2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor
2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider() at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance() at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure
1 accessor)
at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure1 accessor) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func
1 factory)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
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'.
PM>
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'.
According to the current design, you cannot use AppUser
in EntityFrameworkCore.DbMigrations
.
AppUser
and IdentityUser
are shared tables, you can use IdentityUser(FullAuditedEntityWithUser<Guid, IdentityUser>)
.
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'.
According to the current design, you cannot use
AppUser
inEntityFrameworkCore.DbMigrations
.
AppUser
andIdentityUser
are shared tables, you can useIdentityUser(FullAuditedEntityWithUser<Guid, IdentityUser>)
.
Yes, I see, there are also some issues using IdentityUser, I'll try to reproduce to you.
Hi @maliming , I have reproduced the issue, please down the demo and do below steps:
@GerryGe That's the problem
@XuJin186 @GerryGe
It is not recommended that you use Entity in other modules as the navigation property, because the module entity may exist in another database. Of course, you can use the Id of the entity.
Even if all modules exist in a database, EF Core will still throw an exception because of different DbContext
, such as the above exception information. (IdentityUserLogin 'requires a primary key to be defined.
). The configuration of the entity is associated with DbContext
.
Maybe classes like FullAuditedEntityWithUser
should be removed from the framework.
In short, don't use FullAuditedEntityWithUser
but use the Id of User entity to query User's information.
@maliming Do you have any idea or background of why define these *WithUser class?
Maybe classes like FullAuditedEntityWithUser should be removed from the framework.
@hikalkan what do you think?
I implemented it and sending the modified source code:
As a general principle; MigrationDbContext should not know the AppUser and ProjectDbContext should not know the IdentityUser. You must ignore related properties where needed.
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<AppUser>(b =>
{
b.ToTable("User", AbpIdentityDbProperties.DbTablePrefix + "Users"); //Sharing the same table "AbpUsers" with the IdentityUser
b.ConfigureByConvention();
b.ConfigureAbpUser();
});
builder.ConfigureDemo(); //Shared code between db contexts
builder.Entity<Test>(b =>
{
//SET RELATIONS FOR THE PROJECT DBCONTEXT
b.HasOne(x => x.Creator).WithMany().IsRequired(false);
b.HasOne(x => x.LastModifier).WithMany().IsRequired(false);
b.HasOne(x => x.Deleter).WithMany().IsRequired(false);
});
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureIdentity();
builder.ConfigureIdentityServer();
builder.ConfigureFeatureManagement();
builder.ConfigureTenantManagement();
//IGNORE AppUser related properties
builder.Entity<Test>(b =>
{
b.Ignore(x => x.Creator);
b.Ignore(x => x.LastModifier);
b.Ignore(x => x.Deleter);
});
builder.ConfigureDemo(); //Shared code between db contexts
}
public class Test : FullAuditedEntityWithUser<Guid, AppUser>
{
public string Name { get; set; }
public string Code { get; set; }
}
This is how we can add navigation properties to an entity defined in a module.
@maliming, removing FullAuditedEntityWithUser
doesn't solve problems, because people will then add navigation properties themselves. But I also don't like this class much to be honest :)
After my testing, the solution is not available, I made some changes:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<AppUser>(b =>
{
b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users"); //Sharing the same table "AbpUsers" with the IdentityUser
b.ConfigureByConvention();
b.ConfigureAbpUser();
});
builder.ConfigureDemo(); //Shared code between db contexts
builder.Entity<Test>(b =>
{
//SET RELATIONS FOR THE PROJECT DBCONTEXT
b.HasOne(x => x.Creator).WithMany().HasForeignKey("CreatorId").IsRequired(false);
b.HasOne(x => x.LastModifier).WithMany().HasForeignKey("LastModifierUserId").IsRequired(false);
b.HasOne(x => x.Deleter).WithMany().HasForeignKey("DeleterUserId").IsRequired(false);
});
}
public static class DemoDbContextModelCreatingExtensions
{
public static void ConfigureDemo(this ModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
builder.Entity<Test>(b =>
{
b.ToTable("Tests");
b.ConfigureByConvention();
b.Property(x => x.Name).IsRequired(false).HasMaxLength(200);
});
/* Configure your own tables/entities inside here */
//builder.Entity<YourEntity>(b =>
//{
// b.ToTable(DemoConsts.DbTablePrefix + "YourEntities", DemoConsts.DbSchema);
// //...
//});
}
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureIdentity();
builder.ConfigureIdentityServer();
builder.ConfigureFeatureManagement();
builder.ConfigureTenantManagement();
//IGNORE AppUser related properties
builder.Entity<Test>(b =>
{
b.Ignore(x => x.Creator);
b.Ignore(x => x.LastModifier);
b.Ignore(x => x.Deleter);
b.HasOne<IdentityUser>().WithMany().HasForeignKey("CreatorId").IsRequired(false);
b.HasOne<IdentityUser>().WithMany().HasForeignKey("LastModifierUserId").IsRequired(false);
b.HasOne<IdentityUser>().WithMany().HasForeignKey("DeleterUserId").IsRequired(false);
});
builder.ConfigureDemo(); //Shared code between db contexts
}
public class Test : FullAuditedEntityWithUser<Guid, AppUser>
{
public string Name { get; set; }
public string Code { get; set; }
}
There is still an issue with the solution provided in the article https://community.abp.io/articles/abp-suite-how-to-add-the-user-entity-as-a-navigation-property-of-another-entity-furp75ex
hi @albutta
Please create a new issue.
if it's related to abp commercial please get support via the support website.
Version: 2.6.2 Entity:
MigrationDbContext:
DbContext:
ConfigureWms:
Exception Information: