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

Support table splitting with HasGeneratedTsVectorColumn #2391

Open
span opened this issue Jun 3, 2022 · 3 comments
Open

Support table splitting with HasGeneratedTsVectorColumn #2391

span opened this issue Jun 3, 2022 · 3 comments
Labels
blocked enhancement New feature or request
Milestone

Comments

@span
Copy link

span commented Jun 3, 2022

I am trying to add owned types to my NpgsqlTsVector column, but when adding the migration it fails with an argument null exception.

Stack trace:

System.ArgumentNullException: Value cannot be null. (Parameter 'property')
   at Microsoft.EntityFrameworkCore.RelationalPropertyExtensions.GetColumnName(IReadOnlyProperty property, StoreObjectIdentifier& storeObject)
   at Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal.NpgsqlAnnotationProvider.<>c__DisplayClass2_1.<For>b__10(String p2)
   at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal.NpgsqlAnnotationProvider.For(IColumn column, Boolean designTime)+MoveNext()
   at Microsoft.EntityFrameworkCore.Infrastructure.AnnotatableBase.AddAnnotations(AnnotatableBase annotatable, IEnumerable`1 annotations)
   at Microsoft.EntityFrameworkCore.Infrastructure.AnnotatableBase.AddAnnotations(IEnumerable`1 annotations)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.RelationalModel.Create(IModel model, IRelationalAnnotationProvider relationalAnnotationProvider, Boolean designTime)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.RelationalModel.Add(IModel model, IRelationalAnnotationProvider relationalAnnotationProvider, Boolean designTime)
   at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelRuntimeInitializer.InitializeModel(IModel model, Boolean designTime, Boolean prevalidation)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelRuntimeInitializer.Initialize(IModel model, Boolean designTime, IDiagnosticsLogger`1 validationLogger)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_DesignTimeModel()
   at Microsoft.EntityFrameworkCore.Metadata.Internal.DesignTimeModel.get_Model()
   at Microsoft.EntityFrameworkCore.Design.DesignTimeServiceCollectionExtensions.<>c__DisplayClass1_0.<AddDbContextDesignTimeServices>b__10(IServiceProvider _)
   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 callSite, 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 callSite, 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 callSite, 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__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.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.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Value cannot be null. (Parameter 'property')

Config (firstname is string, adress is owned type):

        modelBuilder.Entity<CustomerDao>().OwnsOne(k => k.Address);
        modelBuilder.Entity<CustomerDao>()
            .HasGeneratedTsVectorColumn(
                p => p.SearchVector,
                "english",  // Text search config
                p => new { p.FirstName, p.Address})
            .HasIndex(p => p.SearchVector)
            .HasMethod("GIN"); //

I can't find any references or examples where owned types are used for the search column so perhaps this is not supported? Any way to work around it? Perhaps serialize into a json column?

@roji
Copy link
Member

roji commented Jun 3, 2022

You cannot include an entity type directly in HasGeneratedTsVectorColumn - you must reference specific columns you want included.

However, unfortunately drilling into an owned entity is also unsupported at the moment - see dotnet/efcore#11336 for a very similar issue for indexes with EF Core (once that's done, we can do the same thing here).

The good news is that it's easy to work around this: HasGeneratedTsVectorColumn is nothing but sugar over HasComputedColumnSql. So you can simply configure SearchVector with HasComputedColumn and directly provide the SQL to reference the columns you want. This typically would something like the following:

modelBuilder.Entity<Blog>().Property(b => b.TsVector)
    .HasComputedColumnSql(@"to_tsvector('english', ""FirstName"", ""Address_Something"")");

I'll leave this open to track adding support to HasGeneratedTsVectorColumn someday.

@roji roji added enhancement New feature or request blocked labels Jun 3, 2022
@roji roji added this to the Backlog milestone Jun 3, 2022
@roji roji changed the title Full text search with owned types Support table splitting with HasGeneratedTsVectorColumn Jun 3, 2022
@span
Copy link
Author

span commented Jun 3, 2022

Wow, very interesting. Thank you for your quick reply.

When using HasComputedColumnSql, there is no need/possibility to specify HasIndex and HasMethod?

@roji
Copy link
Member

roji commented Jun 3, 2022

@span no, you still need to specify HasIndex if you want an index. HasComputedColumnSql only creates the computed column - it does not create an index for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocked enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants