Base solution for your next web application
Open Closed

Query an entity without knowing the object type in advance #3875


User avatar
0
jcompagnon created

Hello,

I'm wondering, if it's possible in the first place, how I would go about querying the database (using EF) using an ID and a table name.

For example:

QueryDynamicData(string tableName, long entityID){
return GetItem(tableName, entityID);
}

And could be called like:

var entry = QueryDynamicData("Person", 143);

Thanks in advance!


18 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @JCompagnon,

    ABP does not offer anything for this but EF might support it, have you checked it on the web ?

    Thanks.

  • User Avatar
    0
    jcompagnon created

    I have done some googling, but nothing useful so far has come up. I've posted a question on Stack Overflow, we'll see if anything comes of it.

    Thanks for your input!

  • User Avatar
    0
    jcompagnon created

    I posted the question on Stack Overflow and got some good answers. <a class="postlink" href="https://stackoverflow.com/questions/46285519/query-an-entity-framework-entity-without-knowing-the-object-type-class-table-i">https://stackoverflow.com/questions/462 ... ss-table-i</a>

    I'm wondering now where would I put such a function?

    I've tried adding it to the ProjectRepositoryBase.cs where it says to add common methods:

    public abstract class FirstASPNetZeroRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<FirstASPNetZeroDbContext, TEntity, TPrimaryKey>
            where TEntity : class, IEntity<TPrimaryKey>
        {
            protected FirstASPNetZeroRepositoryBase(IDbContextProvider<FirstASPNetZeroDbContext> dbContextProvider)
                : base(dbContextProvider)
            {
    
            }
    
            //add your common methods for all repositories
            public object[] QueryDynamicData(string table, int entityID)
            {
                try
                {
                    
                }catch(Exception e) { }
                return null;
            }
        }
    

    However, when I go to an AppService class, I cannot access that method from the repository (_patientRepository will not find method QueryDyanmicData() from above)

    public class PatientAppService : FirstASPNetZeroAppServiceBase, IPatientAppService
        {
            private readonly IRepository<PatientItem> _patientRepository;
    
            public PatientAppService(IRepository<PatientItem> patientRepository)
            {
                _patientRepository = patientRepository;
            }
    
            public async Task<PagedResultDto<PatientListDto>> GetPatientsForGrid(GetPatientsInput input)
            {
                _patientRepository
    //...other code
    

    Thanks!

  • User Avatar
    0
    jcompagnon created

    An update:

    For now I've put the function in the AppServiceBase class in the application layer. I'm sure I'm breaking a whole lot of Best Practices, but as a rough draft / proof of concept:

    public abstract class FirstASPNetZeroAppServiceBase : ApplicationService
        {
            private static readonly FirstASPNetZeroDbContext _dbContext = new FirstASPNetZeroDbContext();
            private static readonly object _dbContextLock = new object();
    
            protected FirstASPNetZeroDbContext DBContext
            {
                get
                {
                    lock (_dbContextLock)
                    {
                        return _dbContext;
                    }
                }
            }
    
    protected virtual List<Dictionary<string, object>> QueryDynamicData(string table, int entityID)
            {
                try
                {
                    //Get the table desired based on the table name passed
                    PropertyInfo dbSetInfo = DBContext.GetType().GetProperties().FirstOrDefault(p => p.Name.ToLower().Equals(table.ToLower()));
    
                    //Return all results from the table into IQueryable set where Id = entityID passed
                    IQueryable anyDbSet = ((IQueryable)dbSetInfo.GetValue(DBContext)).Where("Id=" + entityID);
    
                    List<Dictionary<string,object>> listObjects = new List<Dictionary<String, Object>>();
    
                    //Iterate through results
                    foreach (Object entity in anyDbSet)
                    {
                        //Create dictionary of Field Name, Field Value from results
                        Dictionary<string, object> listDBValues = entity.GetType().GetProperties().ToDictionary(propertyInfo => propertyInfo.Name, propertyInfo => propertyInfo.GetValue(entity));
    
                        //Add dictionary to list of dictionaries - useful for returning list of found results instead of just one
                        listObjects.Add(listDBValues);
                    }
    
                    //Return list of dictionaries
                    return listObjects;
                }
                catch (Exception e) { }
                return null;
            }protected virtual List<Dictionary<string, object>> QueryDynamicData(string table, int entityID)
            {
                try
                {
                    //Get the table desired based on the table name passed
                    PropertyInfo dbSetInfo = DBContext.GetType().GetProperties().FirstOrDefault(p => p.Name.ToLower().Equals(table.ToLower()));
    
                    //Return all results from the table into IQueryable set where Id = entityID passed
                    IQueryable anyDbSet = ((IQueryable)dbSetInfo.GetValue(DBContext)).Where("Id=" + entityID);
    
                    List<Dictionary<string,object>> listObjects = new List<Dictionary<String, Object>>();
    
                    //Iterate through results
                    foreach (Object entity in anyDbSet)
                    {
                        //Create dictionary of Field Name, Field Value from results
                        Dictionary<string, object> listDBValues = entity.GetType().GetProperties().ToDictionary(propertyInfo => propertyInfo.Name, propertyInfo => propertyInfo.GetValue(entity));
    
                        //Add dictionary to list of dictionaries - useful for returning list of found results instead of just one
                        listObjects.Add(listDBValues);
                    }
    
                    //Return list of dictionaries
                    return listObjects;
                }
                catch (Exception e) { }
                return null;
            }
    
  • User Avatar
    0
    pankajmathur created

    Hi,

    I have the same problem. Earlier I was using ASP.Net MVC 5.x with JQuery. In this version I had made the <ProjectName>RepositoryBase class to public from protected and also its constructor to public from protected. After this I inject this in my Service constructor and I was getting the repository successfully. Once I had the repository, I was successfully calling the common methods written in <ProjectName>RepositoryBase class. Now I am using .Net Core With MVC and JQuery. I tried doing same thing here, i.e making the <ProjectName>RepositoryBase class to public from protected and also its constructor to public from protected. But when I inject this in my service constructor, I do not get the value. Instead I get the error saying service depends on <ProjectName>RepositoryBase which is not registered.

    Any help on this would be appreciated.

    Regards, Mahendra

  • User Avatar
    0
    pankajmathur created

    Just to add to my above post, here is the exact error that I get.

    An unhandled exception occurred while processing the request.

    HandlerException: Can't create component 'CitiXsys.iVend365.Surcharges.SurchargeAppService' as it has dependencies to be satisfied.

    'CitiXsys.iVend365.Surcharges.SurchargeAppService' is waiting for the following dependencies:

    • Service 'CitiXsys.iVend365.EntityFrameworkCore.Repositories.iVend365RepositoryBase`2[[CitiXsys.iVend365.Surcharges.Surcharge, CitiXsys.iVend365.Core, Version=4.1.0.0, Culture=neutral, PublicKeyToken=null],[System.Int64, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]' which was not registered. Castle.MicroKernel.Handlers.DefaultHandler.AssertNotWaitingForDependency()
  • User Avatar
    0
    aaron created
    Support Team

    Does reverting it to public work?

  • User Avatar
    0
    pankajmathur created

    No. In ASP.Net version it worked, But in .Net Core version it did not work.

  • User Avatar
    0
    aaron created
    Support Team

    Check that you added AutoRepositoryTypes attribute to your DbContext (see docs).

  • User Avatar
    0
    pankajmathur created

    When I added AutoRepositoryTypes, and run the application I an not even getting the login screen. Instead I an getting the following error.

    An error occurred while starting the application.

    MissingMethodException: Constructor on type 'CitiXsys.iVend365.EntityFrameworkCore.Repositories.iVend365RepositoryBase`1[[Abp.Localization.ApplicationLanguage, Abp.Zero.Common, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null]]' not found. System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, ref StackCrawlMark stackMark)

    ArgumentException: Type CitiXsys.iVend365.EntityFrameworkCore.Repositories.iVend365RepositoryBase`1[[Abp.Localization.ApplicationLanguage, Abp.Zero.Common, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null]] does not have a public default constructor and could not be instantiated. Castle.Core.Internal.ReflectionUtil.Instantiate<TBase>(Type subtypeofTBase, Object[] ctorArgs)

    ComponentActivatorException: ComponentActivator: could not instantiate CitiXsys.iVend365.EntityFrameworkCore.Repositories.iVend365RepositoryBase`1[[Abp.Localization.ApplicationLanguage, Abp.Zero.Common, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null]] Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateInstanceCore(ConstructorCandidate constructor, Object[] arguments, Type implType)

    MissingMethodException: Constructor on type 'CitiXsys.iVend365.EntityFrameworkCore.Repositories.iVend365RepositoryBase`1[[Abp.Localization.ApplicationLanguage, Abp.Zero.Common, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null]]' not found. System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, ref StackCrawlMark stackMark) System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) System.Activator.CreateInstance(Type type, Object[] args) Castle.Core.Internal.ReflectionUtil.Instantiate<TBase>(Type subtypeofTBase, Object[] ctorArgs)

    Show raw exception details ArgumentException: Type CitiXsys.iVend365.EntityFrameworkCore.Repositories.iVend365RepositoryBase`1[[Abp.Localization.ApplicationLanguage, Abp.Zero.Common, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null]] does not have a public default constructor and could not be instantiated. Castle.Core.Internal.ReflectionUtil.Instantiate

    Show raw exception details ComponentActivatorException: ComponentActivator: could not instantiate CitiXsys.iVend365.EntityFrameworkCore.Repositories.iVend365RepositoryBase`1[[Abp.Localization.ApplicationLanguage, Abp.Zero.Common, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null]] Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateInstanceCore(ConstructorCandidate constructor, Object[] arguments, Type implType) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateInstance(CreationContext context, ConstructorCandidate constructor, Object[] arguments) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.InternalCreate(CreationContext context) Castle.MicroKernel.ComponentActivator.AbstractComponentActivator.Create(CreationContext context, Burden burden) Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.CreateInstance(CreationContext context, bool trackedExternally) Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy) Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, bool requiresDecommission, bool instanceRequired, out Burden burden) Castle.MicroKernel.Handlers.DefaultHandler.Resolve(CreationContext context, bool instanceRequired) Castle.MicroKernel.Resolvers.DefaultDependencyResolver.Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateConstructorArguments(ConstructorCandidate constructor, CreationContext context) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.Instantiate(CreationContext context) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.InternalCreate(CreationContext context) Castle.MicroKernel.ComponentActivator.AbstractComponentActivator.Create(CreationContext context, Burden burden) Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.CreateInstance(CreationContext context, bool trackedExternally) Castle.MicroKernel.Lifestyle.SingletonLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy) Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, bool requiresDecommission, bool instanceRequired, out Burden burden) Castle.MicroKernel.Handlers.DefaultHandler.Resolve(CreationContext context, bool instanceRequired) Castle.MicroKernel.Resolvers.DefaultDependencyResolver.Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateConstructorArguments(ConstructorCandidate constructor, CreationContext context) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.Instantiate(CreationContext context) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.InternalCreate(CreationContext context) Castle.MicroKernel.ComponentActivator.AbstractComponentActivator.Create(CreationContext context, Burden burden) Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.CreateInstance(CreationContext context, bool trackedExternally) Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy) Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, bool requiresDecommission, bool instanceRequired, out Burden burden) Castle.MicroKernel.Handlers.DefaultHandler.Resolve(CreationContext context, bool instanceRequired) Castle.MicroKernel.Resolvers.DefaultDependencyResolver.Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateConstructorArguments(ConstructorCandidate constructor, CreationContext context) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.Instantiate(CreationContext context) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.InternalCreate(CreationContext context) Castle.MicroKernel.ComponentActivator.AbstractComponentActivator.Create(CreationContext context, Burden burden) Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.CreateInstance(CreationContext context, bool trackedExternally) Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy) Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, bool requiresDecommission, bool instanceRequired, out Burden burden) Castle.MicroKernel.Handlers.DefaultHandler.Resolve(CreationContext context, bool instanceRequired) Castle.MicroKernel.Resolvers.DefaultDependencyResolver.Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateConstructorArguments(ConstructorCandidate constructor, CreationContext context) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.Instantiate(CreationContext context) Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.InternalCreate(CreationContext context) Castle.MicroKernel.ComponentActivator.AbstractComponentActivator.Create(CreationContext context, Burden burden) Castle.MicroKernel.Lifestyle.AbstractLifestyleManager.CreateInstance(CreationContext context, bool trackedExternally) Castle.MicroKernel.Lifestyle.SingletonLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy) Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, bool requiresDecommission, bool instanceRequired, out Burden burden) Castle.MicroKernel.Handlers.DefaultHandler.Resolve(CreationContext context, bool instanceRequired) Castle.MicroKernel.DefaultKernel.ResolveComponent(IHandler handler, Type service, IDictionary additionalArguments, IReleasePolicy policy) Castle.MicroKernel.DefaultKernel.Castle.MicroKernel.IKernelInternal.Resolve(Type service, IDictionary arguments, IReleasePolicy policy) Castle.Windsor.WindsorContainer.Resolve<T>() Abp.AbpKernelModule.PostInitialize() in AbpKernelModule.cs System.Collections.Generic.List.ForEach(Action<T> action) Abp.AbpBootstrapper.Initialize() in AbpBootstrapper.cs Abp.AspNetCore.AbpApplicationBuilderExtensions.UseAbp(IApplicationBuilder app, Action<AbpApplicationBuilderOptions> optionsAction) in AbpApplicationBuilderExtensions.cs CitiXsys.iVend365.Web.Startup.Startup.Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) in Startup.cs + app.UseAbp(options => System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() Microsoft.AspNetCore.Hosting.ConventionBasedStartup.Configure(IApplicationBuilder app) Microsoft.AspNetCore.ApplicationInsights.HostingStartup.ApplicationInsightsLoggerStartupFilter+<>c__DisplayClass0_1.<Configure>b__0(IApplicationBuilder builder) Microsoft.ApplicationInsights.AspNetCore.ApplicationInsightsStartupFilter+<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app) Microsoft.AspNetCore.Server.IISIntegration.IISSetupFilter+<>c__DisplayClass3_0.<Configure>b__0(IApplicationBuilder app) Microsoft.AspNetCore.Hosting.Internal.AutoRequestServicesStartupFilter+<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder builder) Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()

    Show raw exception details .NET Core 4.6.00001.0 X64 v4.0.0.0 | Microsoft.AspNetCore.Hosting version 2.0.0-rtm-26452 | Microsoft Windows 10.0.15063 | Need help?

  • User Avatar
    0
    aaron created
    Support Team

    It says right there:

    ArgumentException: Type CitiXsys.iVend365.EntityFrameworkCore.Repositories.iVend365RepositoryBase`1[[Abp.Localization.ApplicationLanguage, Abp.Zero.Common, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null]] does not have a public default constructor and could not be instantiated.

    You need to provide a public default constructor.

  • User Avatar
    0
    pankajmathur created

    Not sure why its saying that.....I trust ABP already provides the default public constructor... See below code..

    public class iVend365RepositoryBase<TEntity, TPrimaryKey> : EfCoreRepositoryBase<iVend365DbContext, TEntity, TPrimaryKey> where TEntity : class, IEntity<TPrimaryKey> {

        public iVend365RepositoryBase(IDbContextProvider&lt;iVend365DbContext&gt; dbContextProvider)
            : base(dbContextProvider)
        {
    
    
    
        }
    

    ...... ...... ......

  • User Avatar
    0
    aaron created
    Support Team

    Check that you have the following in your module:

    public override void Initialize()
    {
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
    }
    
  • User Avatar
    0
    pankajmathur created

    yes, it's there....see below...

    public override void Initialize() { IocManager.RegisterAssemblyByConvention(typeof(iVend365EntityFrameworkCoreModule).GetAssembly()); }

  • User Avatar
    0
    aaron created
    Support Team

    How are you injecting iVend365RepositoryBase?

  • User Avatar
    0
    pankajmathur created

    Like below...

    public class SurchargeAppService : iVend365AppServiceBase, ISurchargeAppService { private readonly IRepository<Surcharge, long> _SurchargeRepository; private readonly iVend365RepositoryBase<Surcharge, long> _iVendRepository; private readonly IRepository<TaxCode, long> _TaxCodeRepository; private readonly IBackgroundJobManager _backgroundJobManager;

        public SurchargeAppService(iVend365RepositoryBase&lt;Surcharge, long&gt; iVendRepository, IRepository&lt;Surcharge, long&gt; SurchargeRepository, IRepository&lt;TaxCode, long&gt; TaxCodeRepository, IBackgroundJobManager backgroundJobManager)
        {
            _iVendRepository = iVendRepository;
            _SurchargeRepository = SurchargeRepository;            
            _TaxCodeRepository = TaxCodeRepository;
            _backgroundJobManager = backgroundJobManager;
    
            
        }
    
  • User Avatar
    0
    aaron created
    Support Team

    Ah, since you're not using an interface, it won't be registered by convention. You should do self-registration.

    IocManager.Register<iVend365RepositoryBase>(DependencyLifeStyle.Transient);
    
  • User Avatar
    0
    pankajmathur created

    Thanks aaron.....Much appreciated....the problem is sorted out by registering....