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

AbpDbContext.OnModelCreating issue #4582

Closed
zhk0603 opened this issue Jul 2, 2020 · 2 comments · Fixed by #4595
Closed

AbpDbContext.OnModelCreating issue #4582

zhk0603 opened this issue Jul 2, 2020 · 2 comments · Fixed by #4595
Assignees
Milestone

Comments

@zhk0603
Copy link

zhk0603 commented Jul 2, 2020

abp version 3.0.0
ef core 3.1.5

My entity:

public class WorkflowInstanceEntity : FullAuditedAggregateRoot<int>, IMultiTenant
{
    //other properties
    public ICollection<LogEntry> ExecutionLog { get ; set ; }
    //other properties
}

LogEntry :

    classe publique LogEntry
    {
        chaîne publique ActivityId { get ; set ; }
        public Instant Timestamp { get ; set ; } // using NodaTime , key point!!
        public bool Faulted { get ; set ; }
        public string Message { get ; set ; }
    }

DbContext:

    public class ElsaContext : AbpDbContext<ElsaContext>
    {
        public ElsaContext(DbContextOptions<ElsaContext> options) : base(options)
        {
        }

        public DbSet<WorkflowInstanceEntity> WorkflowInstances { get; set; }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder); // key point!!

            builder.ConfigureElsa();
        }
    }

ElsaDbContextModelCreatingExtensions.cs

builder.Entity<WorkflowInstanceEntity>(b =>
{
    b.Property(x => x.ExecutionLog)
                    .HasConversion(x => serialized operation,
                        x => deserialization operation);
}

up to this point, everything works fine, "Update-database" is executed, it is generated correctly, and the ExecutionLog field is also of type string.

however, at runtime, ef core throws an exception.

System.InvalidOperationException: The property 'LogEntry.Timestamp' could not be mapped, because it is of type 'Instant' 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, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.SqlServer.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger`1 logger)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.ValidatingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext`1 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.CallSiteVisitor`2.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.CallSiteVisitor`2.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.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_Model()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.CheckState()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.Include[TEntity,TProperty](IQueryable`1 source, Expression`1 navigationPropertyPath)
   at Elsa.Persistence.EntityFrameworkCore.Services.EntityFrameworkCoreWorkflowDefinitionStore.ListAsync(VersionOptions version, CancellationToken cancellationToken) in D:\Workspaces\01.github\zhk0603\sy-workflow\Sy.Abp.Elsa\Sy.Abp.Elsa.Persistence.EntityFrameworkCore\Services\EntityFrameworkCoreWorkflowDefinitionStore.cs:line 109
   at Elsa.WorkflowProviders.StoreWorkflowProvider.GetWorkflowDefinitionsAsync(CancellationToken cancellationToken)
   at Elsa.Services.WorkflowRegistry.LoadWorkflowDefinitionsAsync(CancellationToken cancellationToken)
   at Elsa.Services.WorkflowRegistry.<>c__DisplayClass7_0.<<ReadCacheAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.Extensions.Caching.Memory.CacheExtensions.GetOrCreateAsync[TItem](IMemoryCache cache, Object key, Func`2 factory)
   at Elsa.Services.WorkflowRegistry.ReadCacheAsync(CancellationToken cancellationToken)
   at Elsa.Services.WorkflowRegistry.ListByStartActivityAsync(String activityType, CancellationToken cancellationToken)
   at Elsa.Activities.Http.RequestHandlers.Handlers.TriggerRequestHandler.HandleRequestAsync()
   at Elsa.Activities.Http.Middleware.RequestHandlerMiddleware`1.InvokeAsync(HttpContext httpContext, THandler handler)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

If base. onModelCreating(builder); is not called in OnModelCreating, everything is fine.

    public class ElsaContext : AbpDbContext<ElsaContext>
    {
        public ElsaContext(DbContextOptions<ElsaContext> options) : base(options)
        {
        }

        public DbSet<WorkflowInstanceEntity> WorkflowInstances { get; set; }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            // base.OnModelCreating(builder);  // Don't call it.
            builder.ConfigureElsa();
        }
    }

I try the following changes

    public class ElsaContext : AbpDbContext<ElsaContext>
    {
        public ElsaContext(DbContextOptions<ElsaContext> options) : base(options)
        {
        }

        public DbSet<WorkflowInstanceEntity> WorkflowInstances { get; set; }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            // base.OnModelCreating(builder); // Don't call it.
            modelBuilder.Entity<LogEntry>(); // throw an exception
            builder.ConfigureElsa();
        }
    }

I tried to track down the issue and I found that in the AbpDbContext ConfigureBaseProperties method.

if (mutableEntityType.IsOwned())
{
    return;
}
modelBuilder.Entity<TEntity>().ConfigureByConvention(); // Why isn't it called only by entities that inherit from IEntity?
ConfigureGlobalFilters<TEntity>(modelBuilder, mutableEntityType);
@realLiangshiwei
Copy link
Member

realLiangshiwei commented Jul 2, 2020

Hi,

This is a bug, we should not configure classes that are not entities.

Try to override ConfigureBaseProperties method in your dbcontext:

protected override void ConfigureBaseProperties<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
{
    if (!typeof(IEntity).IsAssignableFrom(typeof(TEntity)))
    {
        return;
    }
    base.ConfigureBaseProperties<TEntity>(modelBuilder, mutableEntityType);
}

@zhk0603
Copy link
Author

zhk0603 commented Jul 2, 2020

thanks

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

Successfully merging a pull request may close this issue.

2 participants