Custom plugin with multiple tables Nop 4.1

2 years ago
I am trying to write a custom plugin that creates multiple tables on install. Everything works fine with one table and the code below. but if I try to do two tables I get an Ambiguous error message

Search the internet but can not find the solution. Any help would be appreciated.

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfiguration(new Table1RecordMap());
            base.OnModelCreating(modelBuilder);

            //modelBuilder.ApplyConfiguration(new Table2RecordMap());
            //base.OnModelCreating(modelBuilder);
        }
2 years ago
Hi,

Can you share full error message?

Also make sure table names are unique and EntityMap class file.
2 years ago
This is the error message... The table names are unique

"Ambiguous match found."

"   at System.RuntimeType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)\r\n   at System.Type.GetProperty(String name, BindingFlags bindingAttr)\r\n   at System.SharedTypeExtensions.GetPropertiesInHierarchy(Type type, String name)+MoveNext()\r\n   at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Func`2 predicate, Boolean& found)\r\n   at System.Reflection.PropertyInfoExtensions.FindSetterProperty(PropertyInfo propertyInfo)\r\n   at System.Reflection.PropertyInfoExtensions.IsCandidateProperty(PropertyInfo propertyInfo, Boolean needsWrite, Boolean publicOnly)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Internal.MemberClassifier.FindCandidateNavigationPropertyType(PropertyInfo propertyInfo)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.RelationshipDiscoveryConvention.GetNavigationCandidates(EntityType entityType)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.RelationshipDiscoveryConvention.FindRelationshipCandidates(InternalEntityTypeBuilder entityTypeBuilder)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.RelationshipDiscoveryConvention.DiscoverRelationships(InternalEntityTypeBuilder entityTypeBuilder)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnEntityTypeAdded(InternalEntityTypeBuilder entityTypeBuilder)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.RunVisitor.VisitOnEntityTypeAdded(OnEntityTypeAddedNode node)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionVisitor.VisitConventionScope(ConventionScope node)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Run()\r\n   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalModelBuilder.Entity(TypeIdentity& type, ConfigurationSource configurationSource, Boolean throwOnQuery)\r\n   at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalModelBuilder.Entity(Type type, ConfigurationSource configurationSource, Boolean throwOnQuery)\r\n   at Microsoft.EntityFrameworkCore.ModelBuilder.Entity[TEntity]()\r\n   at Microsoft.EntityFrameworkCore.ModelBuilder.ApplyConfiguration[TEntity](IEntityTypeConfiguration`1 configuration)\r\n   at Nop.Plugin.Fanolli.Journal.Data.FanolliJournalObjectContext.OnModelCreating(ModelBuilder modelBuilder)\r\n   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator)\r\n   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)"

{System.Reflection.PropertyInfo GetPropertyImpl(System.String, System.Reflection.BindingFlags, System.Reflection.Binder, System.Type, System.Type[], System.Reflection.ParameterModifier[])}
2 years ago
nopCommerce version ?
2 years ago
latest 4.1
2 years ago
Have you done this before? custom plugin with two tables? Could you share how you do it?
2 years ago
Might be you missing register entity for table 2 in with dbContext in DependencyRegistrar file.


          // for table 1
            builder.RegisterType<EfRepository<DBTable1>>().As<IRepository<DBTable1>>()
                .WithParameter(ResolvedParameter.ForNamed<IDbContext>("your_db_context_name"))
                .InstancePerLifetimeScope();

            // for table 2
            builder.RegisterType<EfRepository<DBTable2>>().As<IRepository<DBTable2>>()
                .WithParameter(ResolvedParameter.ForNamed<IDbContext>("your_db_context_name"))
                .InstancePerLifetimeScope();
2 years ago
You can try this:

DependencyRegistrar;


private const string CONTEXT1_NAME = "nop_object_context_table1";
        private const string CONTEXT2_NAME = "nop_object_context_table2";


Then in Register;


//data context
            builder.RegisterPluginDataContext<Table1DataObjectContext>(CONTEXT1_NAME);
            builder.RegisterPluginDataContext<Table2DataObjectContext>(CONTEXT2_NAME);

            //override required repository with our custom context
            builder.RegisterType<EfRepository<Table1>>().As<IRepository<Table1>>()
                .WithParameter(ResolvedParameter.ForNamed<IDbContext>(CONTEXT1_NAME))
                .InstancePerLifetimeScope();
            //override required repository with our custom context
            builder.RegisterType<EfRepository<Table2>>().As<IRepository<Table2>>()
                .WithParameter(ResolvedParameter.ForNamed<IDbContext>(CONTEXT2_NAME))
                .InstancePerLifetimeScope();


Take a look at Pickup in Store Plugin DependencyRegistrar in Infrastructure folder.
2 years ago
dianoche wrote:
You can try this:

DependencyRegistrar;


private const string CONTEXT1_NAME = "nop_object_context_table1";
        private const string CONTEXT2_NAME = "nop_object_context_table2";


Then in Register;


//data context
            builder.RegisterPluginDataContext<Table1DataObjectContext>(CONTEXT1_NAME);
            builder.RegisterPluginDataContext<Table2DataObjectContext>(CONTEXT2_NAME);

            //override required repository with our custom context
            builder.RegisterType<EfRepository<Table1>>().As<IRepository<Table1>>()
                .WithParameter(ResolvedParameter.ForNamed<IDbContext>(CONTEXT1_NAME))
                .InstancePerLifetimeScope();
            //override required repository with our custom context
            builder.RegisterType<EfRepository<Table2>>().As<IRepository<Table2>>()
                .WithParameter(ResolvedParameter.ForNamed<IDbContext>(CONTEXT2_NAME))
                .InstancePerLifetimeScope();


Take a look at Pickup in Store Plugin DependencyRegistrar in Infrastructure folder.


That sure did help but now I am stuck on the OnModelCreating part... How do I pass more then one entity to the OnModelCreating. Any Idea?


protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfiguration(new Table1RecordMap());
            modelBuilder.ApplyConfiguration(new Table2RecordMap());
            base.OnModelCreating(modelBuilder);
        }
2 years ago
mcselasvegas wrote:
You can try this:

DependencyRegistrar;


private const string CONTEXT1_NAME = "nop_object_context_table1";
        private const string CONTEXT2_NAME = "nop_object_context_table2";


Then in Register;


//data context
            builder.RegisterPluginDataContext<Table1DataObjectContext>(CONTEXT1_NAME);
            builder.RegisterPluginDataContext<Table2DataObjectContext>(CONTEXT2_NAME);

            //override required repository with our custom context
            builder.RegisterType<EfRepository<Table1>>().As<IRepository<Table1>>()
                .WithParameter(ResolvedParameter.ForNamed<IDbContext>(CONTEXT1_NAME))
                .InstancePerLifetimeScope();
            //override required repository with our custom context
            builder.RegisterType<EfRepository<Table2>>().As<IRepository<Table2>>()
                .WithParameter(ResolvedParameter.ForNamed<IDbContext>(CONTEXT2_NAME))
                .InstancePerLifetimeScope();


Take a look at Pickup in Store Plugin DependencyRegistrar in Infrastructure folder.

That sure did help but now I am stuck on the OnModelCreating part... How do I pass more then one entity to the OnModelCreating. Any Idea?


protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfiguration(new Table1RecordMap());
            modelBuilder.ApplyConfiguration(new Table2RecordMap());
            base.OnModelCreating(modelBuilder);
        }


I am not sure if it is possible that way but I always create new DataObjectContext for each context. You will have 2 DataObjectContex File


//data context
            builder.RegisterPluginDataContext<Table1DataObjectContext>(CONTEXT1_NAME);//First One
            builder.RegisterPluginDataContext<Table2DataObjectContext>(CONTEXT2_NAME);//Second One