.net core testing dbsets - c#

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.

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();
}
}

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
}
}

implement stored procedure in code first existing database

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.

Get DbContext from DbSet

I am developing some extensions methods to add some funcionalities for DbSet. However, when creating an "Update" method, I need the DbSet's DbContext to be able to modify the state of a entity. The current implementation:
public void Update<TEntity>(this DbSet<TEntity> repository, TEntity entity) where TEntity : class
{
repository.Attach(entity);
var context = // how get the context from repository?
((IObjectContextAdapter)context).ObjectContext.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
}
Does any one know how to get a DbContext from a DbSet instance?
I've found a better way to accomplish that:
public static void MarkAsModified(this DbContext context, object entity)
{
context.Entry(entity).State = EntityState.Modified;
}

Categories