Base solution for your next web application
Open Closed

Calling stored procedures in Entity Framework #465


User avatar
0
doubledp created

I know that this question of at least a similar question has been asked before. I would like a little more clarity regarding this.

I will have 2 dbContext, 1 connecting to the LOB database and another connecting to a DW database. I have written stored procedures that aggregates data and is returned within the result set.

I would very much like to use entity framework to handle this for me, but I do not want import the tables within that database as I won't be using them directly. My guess is that I need to create entities that will be mapped to the result set of each stored procedure. Would this not create these entities as tables in the database? (This is not what I want)

I am a bit confused as to how to handle this, because I want the dynamic WebAPI functionality to still work and for the functionality to remain very similar as how things are currently being done.

Any guidance will be much appreciated.


5 Answer(s)
  • User Avatar
    0
    ole created

    I did use SQL directly in one of my repository classes.

    public List<ValueDto> GetAll(int id) {

            var ret = Context.Database.SqlQuery&lt;ValueDto&gt;("&lt;SQL returning a result set&gt;").ToList();
            return ret;
        }
    

    The SQL may be a SELECT or an excec of a stored procedure. Entity Framework will try to map the result set to the ValueDto class. Context is defined in the base Abp.EntityFramework.Repositories

    -ole

  • User Avatar
    0
    hikalkan created
    Support Team

    This solution looks fine. Thanks for sharing with us.

  • User Avatar
    0
    doubledp created

    Apologies for only replying now. The repositories is defined within the Entity Framework layer and the DTO's within the Application layer right?

    Currently I have a 2nd dbContext class as per below:

    using System.Data.Common;
    using System.Data.Entity;
    using Abp.EntityFramework;
    using WebApplication.Storage;
    
    namespace WebApplication.EntityFramework
    {
        public class SecondDbContext : AbpDbContext
        {
            public virtual IDbSet<BinaryObject> BinaryObjects { get; set; }
    
            public SecondDbContext() 
                : base("Second")
            {
    
            }
    
            public SecondDbContext(string nameOrConnectionString)
                : base(nameOrConnectionString)
            {
    
            }
    
            public SecondDbContext(DbConnection dbConnection)
                : base(dbConnection, true)
            {
    
            }
        }
    }
    

    Then I have added another it's equivalent base repository class as per below:

    using Abp.Domain.Entities;
    using Abp.EntityFramework;
    using Abp.EntityFramework.Repositories;
    
    namespace WebApplication.EntityFramework.Repositories
    {
        public abstract class SecondRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<SecondDbContext, TEntity, TPrimaryKey>
            where TEntity : class, IEntity<TPrimaryKey>
        {
            protected SecondRepositoryBase(IDbContextProvider<SecondDbContext> dbContextProvider)
                : base(dbContextProvider)
            {
    
            }
        }
    
        public abstract class SecondRepositoryBase<TEntity> : SecondRepositoryBase<TEntity, int>
            where TEntity : class, IEntity<int>
        {
            protected SecondRepositoryBase(IDbContextProvider<SecondDbContext> dbContextProvider)
                : base(dbContextProvider)
            {
    
            }
        }
    }
    

    Do I create a custom repositories for the stored procedures as per your suggestion for each module that I have?

    What I don't understand is in a AppService the IRepository<Entity> is in the constructor that injects the repository accordingly. I assume that this resolved correctly because of the IDbSet<Entity> within the 1st DbContext class.

    How does this then work if I won't have a entity in the newly created 2nd DbContext class?

    Excuse my ignorance, this is fairly new to me and I would really like to understand how everything fits together.

  • User Avatar
    0
    hikalkan created
    Support Team

    Hi,

    Do I create a custom repositories for the stored procedures as per your suggestion for each module that I have?

    It seems like that. If codes are identical, you can create a common repository or a helper class and write SP code in this class and use it from two modules.

    How does this then work if I won't have a entity in the newly created 2nd DbContext class?

    When you create a new entity and add it to the second dbcontext, you can inject IRepository<NewEntity> as normally. ABP understand which dbcontext defines the entity and create correct repository class.

    If same entity is defined in more than one dbcontext, then it resolves the first one. If you need to get a repository for second one, check the module I prepared for the sample:

    <a class="postlink" href="https://github.com/aspnetboilerplate/sample-blog-module/blob/master/src/Abp.Samples.Blog.EntityFramework/AbpZeroSampleDbContext.cs">https://github.com/aspnetboilerplate/sa ... Context.cs</a>

    AutoRepositoryTypes defined repository types for thi dbcontext. And this is the usage:

    <a class="postlink" href="https://github.com/aspnetboilerplate/sample-blog-module/blob/master/src/Abp.Samples.Blog.Application/Posts/PostAppService.cs#L16">https://github.com/aspnetboilerplate/sa ... ice.cs#L16</a>

    So, when you have 2 dbcontextes, you should distinguish them in some level.

  • User Avatar
    0
    doubledp created

    When you create a new entity and add it to the second dbcontext, you can inject IRepository<NewEntity> as normally. ABP understand which dbcontext defines the entity and create correct repository class.

    Does that then mean that I only create the entity in the domain layer and omit the IDbSet<Entity> in the dbContext?

    My understanding is that setting IDbSet<Entity> or DbSet<Entity> is what actually tells EF to create the table on the database when doing a migration.

    I obviously don't want to create tables as I call the SP that aggregates the data and returns it in a result set. Subsequent to that I will also have a SP for the detail of the aggregation as a drilldown.

    Sorry for all the questions; my SQL is stronger than my C# and I am also still getting to grips with O-O programming, as I have come from a procedural language background. :cry: