implement stored procedure in code first existing database - c#

I am working on project using ASP.NET, C#, MVC 5 and Entity Framework. I have implemented generic DBContext and Generic repository and using UnitOfWorks for independent business function, which is all working fine. I need to use stored procedure (that is already saved along with database) with define behavior and I am struggling with that
my stored procedure
USE [DORIS_DB_01]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetFunctionByID](
#FunctionId INT
)
AS
BEGIN
SELECT *
FROM Functions As Fun
WHERE Function_ID = #FunctionId
END
my intention is to call stored procedure in UnitOfWork, if this is correct way
Generic Repository
public interface IGenericRepository<TEntity> : IDisposable where TEntity : class
{
IQueryable<TEntity> GetByIdAsync(int id);
IQueryable<TEntity> GetAll();
}
Repository Implementation
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
protected DbSet<TEntity> _DbSet;
private readonly DbContext _dbContext;
public GenericRepository()
{
}
public GenericRepository(DbContext dbContext)
{
this._dbContext = dbContext;
_DbSet = _dbContext.Set<TEntity>();
}
public IQueryable<TEntity> GetAll()
{
return _DbSet;
}
public IQueryable<TEntity> GetByIdAsync(int id)
{
var receive_ID = id;
return _DbSet;
}
public void Dispose()
{
}
}
rest of code can be found here:
best practice to implement repository pattern and unitOfWork in ASP.NET MVC

I don't know if I understand you well but check http://www.codeproject.com/Questions/677043/Execute-Raw-sql-query-in-entity-framework
this article shows how to execute raw sql query. Now in the repository you can create method 'ExecuteStoredProcedure' to expose it for unit of work.

Related

How to prevent duplicate insertion of record with Entity Framework and repository pattern?

I am using a database-first approach and repository pattern. I am calling third party API recursively to get the data and add the result to my table. When I call third party API, there can be new record or existing records, API will return all data all the time.
I want to prevent duplicate insertion of record in my table.
I am using the repository pattern to save the data.
This is my code:
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private readonly ApplicationDBContext _context;
protected DbSet<T> dbSet;
public GenericRepository(ApplicationDBContext context, ILogger logger)
{
this._context = context;
this.dbSet = context.Set<T>();
}
public virtual async Task<bool> Add(T entity)
{
await dbSet.AddAsync(entity);
return true;
}
}
How can I check if record is already present in table? If already present, then don't add it, else add the record.

generic repository class for multiple databases using EF core

I have multiple databases and I need to connect each database when the user selects from dropdown list. I need to create a generic DBContext which connects to multiple database. I started with this but not going anywhere. This is already existing example but I did not understand what is BaseEntity. I took the help from following link:
Connect multiple Databases to .NET core project via Entity Framework Core
public class GenericRepository<TContext, TEntity> : IGenericRepository<TContext, TEntity>
where TContext : DbContext
where TEntity : BaseEntity
{
private readonly TContext _context;
private DbSet<T> entities;
public GenericRepository(TContext context)
{
_context = context;
entities = context.Set<T>();
}
public List<T> GetAll()
{
return entities.AsNoTracking().ToList();
}
}

.net core testing dbsets

I´m preparing my test infrastructure, but i´m facing some problems with my test repository.
The real repository access EntityFramework DbSet, like this:
public class Repository<T>: IRepository<T> where T : ModelBase
{
protected ApplicationDbContext db;
private DbSet<T> dbSet;
public Repository(ApplicationDbContext db)
{
this.db = db;
dbSet = db.Set<T>();
}
public IQueryable<T> Where(Expression<Func<T, bool>> predicate)
{
return dbSet.Where(predicate).AsNoTracking();
}
....
My TestRepository uses List instead of DbSets:
public class TestRepository<T> : IRepository<T> where T : ModelBase
{
private readonly List<T> dbSet;
protected ApplicationDbContextFake db;
public TestRepository(ApplicationDbContextFake db)
{
this.db = db;
this.dbSet = db.Set<T>();
}
This db.Set<T>() returns a List
The problem occurs when testing my code and there are something like this:
public async Task DeleteAsync()
{
var items = repository.Where(....);
repository.RemoveRange(await items.ToListAsync());
This code runs ok using Entity DbSets, but throws an exception when testing with my TestRepository:
The source IQueryable doesn't implement IAsyncEnumerable. Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.
Any suggestions to workaround this?
If you are using EntityFramework Core (not EF6) - you may use in-memory implementation for your tests.
See docs for Microsoft.EntityFrameworkCore.InMemory provider.

Abstract Entity Framework

I want to create an abstraction layer between Entity Framework and the rest of my application. But I am having a few problems with Entity Framework.
Basically (I don't show you all the interface layers that I've created too), I've split my application into several projects like this :
Domain
Contains my domain object, an abstraction of my datastorage object
DAL
Creates a link between my datastorage and my business layer. Contains two types of elements :
Private ones : my EDMX, my database object, and some other generated objects providing me some useful methods like ToDomain/ToEntity
Public ones : my Data Access Object, providing CRUD methods
Business
Contains the logic of my application. Only knows about the public elements of the DAL and the Domain Layer.
Presentation
Presents the domain objects for the user. Only knows about the business layer.
As I said, I want to create an abstraction of my datastorage objects (in my case Database object, but I want a solution that works also for file or WCF storage for example) so that my business layer don't know anything about my DAL implementation.
Here is a glimpse of what I've done in my DAL :
public abstract class GenericDao<TEntity, TDomain, TDbContext> : IGenericDao<TDomain>
where TDbContext : DbContext, new()
where TEntity : class
where TDomain : class
{
protected TDbContext _context;
protected DbSet<TEntity> _dbSet;
public GenericDao(TDbContext dbContext)
{
this._context = dbContext;
this._dbSet = dbContext.Set<TEntity>();
}
public TDomain Create()
{
return this.ToDomain(this._dbSet.Create());
}
public IList<TDomain> GetAll()
{
return this._dbSet.ToList().Select(entity => this.ToDomain(entity)).ToList();
}
public void Update(TDomain domain)
{
var entity = this.ToEntity(domain);
var entry = this._context.Entry(entity);
entry.State = EntityState.Modified;
}
public void Remove(TDomain domain)
{
_dbSet.Remove(this.ToEntity(domain));
}
protected abstract TDomain ToDomain(TEntity entity);
protected abstract TEntity ToEntity(TDomain domain);
}
You will probably see what's wrong with my code by reading it: when I try to delete or update an entity, I am not manipulating an entity attached to Entity Framework. If I try to attach my entity to the dbContext, it fails because there is already an entity in the context with the same id.
I already thought about several solutions, but none of them please me.
Maybe am I doing something wrong in my approach? I am a little bit confused about the Repository and DAO pattern (I read anything and the very opposite about that difference on the internet).
You have two options:
initialize new dbcontext for each operation and dispose it when operation is ended:
public abstract class GenericDao<TEntity, TDomain, TDbContext> : IGenericDao<TDomain>
where TDbContext : DbContext, new()
where TEntity : class
where TDomain : class
{
protected Func<TDbContext> _contextFactory;
public GenericDao(Func<TDbContext> contextFactory)
{
_contextFactory = contextFactory;
}
public TDomain Create()
{
using(var context = _contextFactory())
{
return context.Set<TEntity>().Create();
}
}
public IList<TDomain> GetAll()
{
using(var context = _contextFactory())
{
return context.Set<TEntity>().ToList()
.Select(entity => this.ToDomain(entity)).ToList();
}
}
public void Update(TDomain domain)
{
using(var context = _contextFactory())
{
var entity = this.ToEntity(domain);
context.Attach(entity);
var entry = this._context.Entry(entity);
entry.State = EntityState.Modified;
context.SaveChanges();
}
}
public void Remove(TDomain domain)
{
using(var context = _contextFactory())
{
var entity = this.ToEntity(domain);
context.Attach(entity);
context.Set<TEntity>.Remove(entity);
context.SaveChanges();
}
}
protected abstract TDomain ToDomain(TEntity entity);
protected abstract TEntity ToEntity(TDomain domain);
}
or you can try to find entity in your instance of dbcontext using property Local of DbSet:
var contextEntity = context.Set<TEntity>().Local
.Where(c=>c.Id == entity.Id).FirstOrDefault();
You seem to be getting stuck coding to an implementation within your abstraction. If you injected an interface to your generic rather than a concrete type (like EF) then your GenericDao becomes much more flexible. You can inject whatever implementation you choose providing it implements the required interface. In your case, WCF, File, Whatever. For example;
protected IDbContext _context;
public GenericDao(IDbContext dbContext)
{
this._context = dbContext;
}
public void Remove(TDomain domain)
{
_context.Remove(this.ToEntity(domain));
}
//abstraction
public interface IDbContext
{
void Remove(Entity entity);
}
//EF Implementation
public MyEfClass : IDbContext
{
public void Remove(Entity entity)
{
//code to remove for EF example
context.Attach(entity);
context.State = EntityState.Modified;
context.Set<TEntity>.Remove(entity);
context.SaveChanges();
}
}
//WCF Implementation
public MyWCFClass : IDbContext
{
public void Remove(Entity entity)
{
//Wcf implementation here
}
}
//File example
public FileWriter : IDbContext
{
public void Remove(Entity entity)
{
LoadFile();
FindEntry(entity);
WriteFile(entity);
SaveFile();
}
public void LoadFile()
{
//use app settings for file directory
}
}

How to write custom methods when using generic repository

I am still struggling to make good data access layer for asp mvc application and as always something is missing :)
I have created separate assembly for DAL and I am using repository pattern and ninject for IOC.
Problem is that now I don't know how to write custom methods (methods out of generic CRUD methods).
This is implementation:
Context class:
public class MainContext : IdentityDbContext<ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IMainContext
{
public MainContext()
: base("DefaultConnection")
{
}
...
public DbSet<Country> Countries { get; set; }
...
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
Repository:
public interface ICountryRepository : IGenericRepository<Country>...
Generic Repository:
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
private readonly IMainContext _context;
private readonly IDbSet<TEntity> _dbSet;
public GenericRepository(IMainContext context)
{
this._context = context;
this._dbSet = context.Set<TEntity>();
}
...
Generic Repository Interface:
public interface IGenericRepository<TEntity> where TEntity : class
{
IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "");
TEntity GetByID(object id);
void Insert(TEntity entity);
void Delete(object id);
void Delete(TEntity entityToDelete);
void Update(TEntity entityToUpdate);
}
And this is try to add custom method in repository class:
public virtual IEnumerable<Country> GetByLocation(float location)
{
var data = from c in _context...
return data;
}
But I don't have a context.
I don't know how to implement getting data now.
Should I inject it somehow or make instance by new keyword (but I guess this is wrong)
How to implement custom method now?
Your implementation of ICountryRepository should inherit the GenericRepository. The GenericRepository has a reference to the db context which you can use for your custom queries. For your Generic Repository constructor is will be much easier to take MainContext instead of an IMainContext which is ok if you keep injecting it down through you layers. With Ninject you will want to bind your MainContext like this:
kernel.Bind<MainContext>().ToSelf().InRequestScope();
and the rest of your interfaces to the concrete implementation. So each of your repositories will have the context through the GenericRepository which has a reference to your db context which you can make custom queries off of in the repository. If you had a service layer, inject the interface of the repository:
private readonly ICountryRepository _repository;
public SomeServie(ICountryRepository repository){
_repository = repository;
}
public void DoSomething(float locationId){
_repository.GetByLocation(locationId);
}
HERE IS THE OTHER CODE YOU NEED:
public class CountryRepository : GenericRepository<Country>, ICountryRepository
{
public CountryRepository(MainContext mainContext) : base(mainContext) { }
public IEnumerable<Country> GetByLocation(float location)
{
return this.Context.Countries.ToList();
}
.....
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
public MainContext Context { get; set; }
public IDbSet<TEntity> DbSet { get; set; }
public GenericRepository(MainContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
.......
Also, your GetCountries does not need to be virtual.
The main changes here are that you need to pass the context through the country repository constructor to base, and the context and countries db set need to be public, even when inherited. See this article: Are private members inherited in C#?

Categories