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 : EfRepositoryBase
            where TEntity : class, IEntity
        {
            protected FirstASPNetZeroRepositoryBase(IDbContextProvider 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 _patientRepository;
    
            public PatientAppService(IRepository patientRepository)
            {
                _patientRepository = patientRepository;
            }
    
            public async Task> 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> 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> listObjects = new List>();
    
                    //Iterate through results
                    foreach (Object entity in anyDbSet)
                    {
                        //Create dictionary of Field Name, Field Value from results
                        Dictionary 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> 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> listObjects = new List>();
    
                    //Iterate through results
                    foreach (Object entity in anyDbSet)
                    {
                        //Create dictionary of Field Name, Field Value from results
                        Dictionary 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(Type subtypeofTBase, Object[] ctorArgs)
    Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateInstanceCore(ConstructorCandidate constructor, Object[] arguments, Type implType)

    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<iVend365DbContext> 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<Surcharge, long> iVendRepository, IRepository<Surcharge, long> SurchargeRepository, IRepository<TaxCode, long> 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(DependencyLifeStyle.Transient);
    
  • User Avatar
    0
    pankajmathur created

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