Core 3.1 EF 6 in Database-first: unable to determine the many-to-many relationship

0

I have a problem with using EF "database-first" in Core 3.1 with many-to-many relationship. There are two tables: ResourcesAZEZ and AsezPoolFileStore And third table AsezPoolFileLink, which contains only two columns: idRes and idFile

Auto-generated code of that classes:

 public partial class AsezPoolFileStore
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public AsezPoolFileStore()
        {
            this.ResourcesAZEZs = new HashSet<ResourcesAZEZ>();
        }
    
        public int id { get; set; }
        public string fileId { get; set; }
        public string filePath { get; set; }
    
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<ResourcesAZEZ> ResourcesAZEZs { get; set; }
    }

public partial class ResourcesAZEZ
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public ResourcesAZEZ()
        {
            this.AsezDictResLinks = new HashSet<AsezDictResLink>();
            this.AsezPoolFileStores = new HashSet<AsezPoolFileStore>();
        }
    
        public int id { get; set; }
        public string id_outer { get; set; }
        public string number_customer { get; set; }
        public string material_text_full { get; set; }
        public string mark { get; set; }
        public string requirements { get; set; }
        public string mark_main { get; set; }
        public string unit { get; set; }
        public Nullable<double> quantity { get; set; }
        public string producer_text { get; set; }
        public string delivery_date { get; set; }
        public Nullable<decimal> price { get; set; }
        public string currency { get; set; }
....
    
        public virtual AsezBSCatalog AsezBSCatalog { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<AsezDictResLink> AsezDictResLinks { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<AsezPoolFileStore> AsezPoolFileStores { get; set; }
    }

And in model.edmx:

          <EntitySetMapping Name="AsezPoolFileStore">
            <EntityTypeMapping TypeName="BCR_ASEZModel.AsezPoolFileStore">
              <MappingFragment StoreEntitySet="AsezPoolFileStore">
                <ScalarProperty Name="id" ColumnName="id" />
                <ScalarProperty Name="fileId" ColumnName="fileId" />
                <ScalarProperty Name="filePath" ColumnName="filePath" />
              </MappingFragment>
            </EntityTypeMapping>
          </EntitySetMapping>

<EntitySetMapping Name="ResourcesAZEZs">
            <EntityTypeMapping TypeName="BCR_ASEZModel.ResourcesAZEZ">
              <MappingFragment StoreEntitySet="ResourcesAZEZ">
                <ScalarProperty Name="winner_okved" ColumnName="winner_okved" />
                <ScalarProperty Name="winner_kpp" ColumnName="winner_kpp" />
                <ScalarProperty Name="winner_inn" ColumnName="winner_inn" />
                <ScalarProperty Name="winner_id_asez" ColumnName="winner_id_asez" />
                <ScalarProperty Name="okved2" ColumnName="okved2" />
                <ScalarProperty Name="okpd2" ColumnName="okpd2" />
                <ScalarProperty Name="dictId" ColumnName="dictId" />
                <ScalarProperty Name="numberpubl" ColumnName="numberpubl" />
                <ScalarProperty Name="previous_ppid" ColumnName="previous_ppid" />
                <ScalarProperty Name="number_cgg" ColumnName="number_cgg" />
...
                <ScalarProperty Name="id_outer" ColumnName="id_outer" />
                <ScalarProperty Name="id" ColumnName="id" />
              </MappingFragment>
            </EntityTypeMapping>
          </EntitySetMapping>


          <AssociationSetMapping Name="AsezPoolFileLink" TypeName="BCR_ASEZModel.AsezPoolFileLink" StoreEntitySet="AsezPoolFileLink">
            <EndProperty Name="ResourcesAZEZ">
              <ScalarProperty Name="id" ColumnName="idRes" />
            </EndProperty>
            <EndProperty Name="AsezPoolFileStore">
              <ScalarProperty Name="id" ColumnName="idFile" />
            </EndProperty>
          </AssociationSetMapping>

Everything look goodm the same as in the article. But for some reasn I'm getting error:

System.InvalidOperationException HResult=0x80131509 Message=Unable to determine the relationship represented by navigation property 'ResourcesAZEZ.AsezPoolFileStores' of type 'ICollection'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'. Source=Microsoft.EntityFrameworkCore StackTrace: at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidatePropertyMapping(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger1 logger) at Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.NpgsqlModelValidator.Validate(IModel model, IDiagnosticsLogger1 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.CallSiteVisitor2.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.CallSiteVisitor2.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.get_DbContextDependencies() at Microsoft.EntityFrameworkCore.DbContext.get_Model() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.get_EntityType() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.CheckState() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.get_EntityQueryable() at Microsoft.EntityFrameworkCore.Internal.InternalDbSet1.System.Linq.IQueryable.get_Provider() at System.Linq.Queryable.Select[TSource,TResult](IQueryable1 source, Expression`1 selector) at KROSS_Core.BLL.ASEZ.GSResourcesAZEZ.GetFilterFieldValues(String entityName) in C:\Estimates Core\KROSS Core\BLL\ASEZ\GSResourcesAZEZ.cs:line 1550 at KROSS_Core.Controllers.GlobalSearchAsezController.AsezFiltersRead(HttpContext context) in C:\Estimates Core\KROSS Core\Controllers\GlobalSearchAsezController.cs:line 489 at KROSS_Core.Controllers.GlobalSearchAsezController.Post() in C:\Estimates Core\KROSS Core\Controllers\GlobalSearchAsezController.cs:line 70 at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<g__Logged|12_1>d.MoveNext()

What am I doing wrong? Or how can I reconfigure relationship to make it working? Or where I can add [NotMapped] attribute in this database-first model? Appreciate for any help!

entity-framework
entity-framework-core
asp.net-core-3.1
ef-core-3.1
asked on Stack Overflow Oct 6, 2020 by G. Goncharov

1 Answer

1

NM relationships in EFCore are a bit tricky. I see you have both ICollection<ResourcesAZEZ> property on AsezPoolFileStore and ICollection<AsezPoolFileStore> on ResourcesAZEZ this is not supported, as you need to have an "relationship entity", which I guess is AsezPoolFileLink.

So you should have a ICollection<AsezPoolFileLink> on both entities. Later you can map those entities to you application model or domain and remove the AsezPoolFileLink intermediate structure, so you can end having the collections you have now. Or always work with the "relationship entity" in between your two entites, up to you.

About your question on how to use [NotMapped] attribute, you do it like this:

[NotMapped]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ResourcesAZEZ> ResourcesAZEZs { get; set; }

This will make any property with this attribute to not being mapped to a field in the database by EFCore.

You can achieve the same functionality using FluentAPI by creating an override of void OnModelCreating(ModelBuilder modelBuilder) method of your DbContext like

public class SomeDbContext : DbContext
{
    public SomeDbContext(DbContextOptions<SomeDbContext> options)
        : base(options)
    {

    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<ResourcesAZEZ>()
        .Ignore(r => r.AsezPoolFileStores);

        modelBuilder.Entity<ResourcesAZEZ>()
        .HasMany(r => r.AsezDictResLinks)
        .WithOne(l => l.Resource);
    }
}

Official documentation on modeling with efcore can be found here https://docs.microsoft.com/en-us/ef/core/modeling/

answered on Stack Overflow Oct 6, 2020 by Pablo Recalde • edited Oct 6, 2020 by Pablo Recalde

User contributions licensed under CC BY-SA 3.0