Abstracting ef core 2 dbContext - entity-framework

I'm trying to make an abstraction over my DB Context layer (EntityFramework 2.0).
Car.DataContext
-------------------
public abstract class BaseCarContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>(e =>
{
e.ToTable("Car");
});
modelBuilder.Entity<Car>(e => { e.ToTable("Cars"); });
}
}
public class CarContext : BaseCarContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (optionsBuilder.IsConfigured)
return;
optionsBuilder.UseSqlServer(#"Server = xxxx; Database = xxxx; Trusted_Connection = True;");
}
public DbSet<Car> Cars { get; set; }
}
Car.Logic
----------------
public interface ICarService
{
GetCarResponse RetrieveCar(int id);
void Save(int id);
...
}
public class CarService : ICarService
{
private readonly ICarService service;
// dbContext interface
public CarService(ICarService service){
this.service = service;
// injecting db context interface
}
public void Save(int id){
... saving using injected db context
// injected db context.Insert(new Car{ Name = "Honda" });
}
...
}
How can I abstract this ef core 2 CarContext in order to use dbContext save
I tried to make an interface IDbContext which is implemented by CarContext
but that way I cannot use dbContext.Cars.Insert because I'm not implementing dbContext cars collection don't have access to ef core methods and properties.
I can use of course concrete implementation but I'm trying to make an abstraction so I can use unit tests, ...
How would you do this?

First, you don't need an abstraction to unit test. EF Core is 100% test-friendly. Second, the only truly acceptable abstractions, in my opinion for EF (or really any ORM) is either a microservice or the CQRS/event sourcing patterns. Those actually add value in that they either fully abstract the dependency and/or solve real line-of-business problems. However, those patterns also require a significant amount of effort to implement correctly, and as such, typically are reserved for large, complex applications.
Long and short, just use EF directly unless you have a truly good reason not to. Testing is not a good reason.

Related

Inherit from DbSet<TEntity> in Entity Framework Code first NullReference

I would like to implement nlog to each action to add an element.
So when I do myContext.Society.Add(), I would like to log something.
I create a class DbSetExtension and modify the context StockContext to use DbSetExtension<T> instead DbSet.
public class DbSetExtension<T> : DbSet<T> where T : class
{
public override T Add(T entity)
{
LoggerInit.Current().Trace("Add Done");
return base.Add(entity);
}
}
When i launch the programm, I notice when I access to myContext.Society.Add.
Society is null. So I think I miss something with my class DbSetExtension but I don't find.
public class StockContext : DbContext
{
public StockContext()
: base("StockContext")
{
}
public DbSet<HistoricalDatas> HistoricalDatas { get; set; }
public DbSet<Society> Society { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Do you have any idea,
Regards,
Alex
[UPDATE]
Code allows to add.
If I replace DbSetExtension by DbSet, the same code works.
So my assumption is I miss something when I inherit from DbSet.
public bool SetSymbols()
{
CsvTools csvThreat = new CsvTools();
List<Eoddata> currentEnum =
csvThreat.ExtractData<Eoddata>(ConfigurationManager.GetString("FilePathQuotes", ""));
currentEnum.ForEach(
c =>
{
//LoggerInit.Current().Trace("Add Done");
Sc.Society.Add(
new Society()
{
RealName = c.Description,
Symbol = String.Format("{0}.PA", c.Symbol),
IsFind = !String.IsNullOrEmpty(c.Description)
});
});
if (Sc.SaveChanges() > 0)
return true;
return false;
}
In my opinion you took totally wrong direction. DbContext is made to work with DbSet and not DbSetExtension class. It is able to instantiate objects of type DbSet and not your own type. This is basically why you get this exception. Reparing it would require probably hacking EF internals and I fear that this problem will be just a beginning for you. Instead I would recommend you to use general way of logging with EF with use of interceptor classes. Here this is explained in details at the end of article Logging and Intercepting Database Operations. Generally this approach would be much more advantageous for you. Why? Because DbContext is just man-in-the-middle in communication with db. In logs you generally cares about what happens to db and its data. Calling Add method on DbSet may not have any effect at all if SaveChanges won't be called lated on. On contrary query interceptors lets you log strictly only interaction with db. Basing on query sent to db you may distinguish what is going on.
But if you instist on your approach I would recommend you using extension methods instead of deriving from DbSet:
public static class DbSetExtensions
{
public static T LoggingAdd<T>(this DbSet<T> dbSet, T entity)
{
LoggerInit.Current().Trace("Add Done");
return dbSet.Add(entity);
}
}
and call it like this:
context.Stock.LoggingAdd(entity);

Entity Framework Repository Pattern - Database Catalogs

I have implemented Repository Pattern and Unit of Work into my ASP.NET Web API project.
It's working great. Now one question came to me about a Repository that can handle all about Setup Catalogs in my application.
Right now I have to create into my Unit of Work all public repositories that make a reference to an EF entity like below:
public IRepository<Document> Document { get { return GetStandardRepo<Document>(); } }
Where Document is an EF Entity. IRepository implements the following methods:
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
IQueryable<T> GetAllReadOnly();
T GetById(int id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(int id);
}
I have about 20 tables for Setup Catalogs in my database so If I follow this pattern I will have to create 20:
public IRepository<SetupEmployeeType> Document { get { return GetStandardRepo<SetupEmployeeType>(); } }
public IRepository<SetupMaritalStatus> Document { get { return GetStandardRepo<SetupMaritalStatus>(); } }
public IRepository<SetupRelationshipCode> Document { get { return GetStandardRepo<SetupRelationshipCode>(); } }
public IRepository<SetupLocationType> Document { get { return GetStandardRepo<SetupLocationType>(); } }
.....
.....
One solution I was thinking is to create my own custom IRepository implementation maybe ICatalogRepository like below:
public class CatalogRepository : EFRepository<EF Entity>, ICatalogRepository
{
public CatalogRepository (DbContext context) : base(context) { }
public IEnumerable<SetupEmployeeType> GetEmployeeTypes()
{
var catalog = DbContext
.Set<SetupEmployeeType>()
.ToList();
return catalog;
}
public IEnumerable<SetupMaritalStatus> GetMaritalStatus()
{
var catalog = DbContext
.Set<SetupMaritalStatus>()
.ToList();
return catalog;
}
}
My question is that CatalogRepository has to inherits from EFRepository but T is not just one entity because I will return diferent entities from diferent methods.
Is that the correct way to do this?
Yeah, don't use this anti pattern (generic repository wrapping DbContext while exposing EF entities). If you really want to use the Repository make the repository interface return ONLY business (or view models if it's a query repo) objects, never IQueryable or other details exposing EF or whatever are you using.
Simply put create a repository for your NEEDS, forget about generic stuff it's an anti pattern. So your CatalogRepository will use a DbContext to issue all the queries needed, then assemble a view model/business object from the results and returns that.
The app will know only about the Repo, never about EF. The queries will remain at the DAL level (not in your app/service/controller) and your app is decoupled, Separation of Concerns is respected.
A class wrapping DbContext is at best useless (what value does it bring?) and at worst a leaky abstraction. Make your life easier, if you want to work directly with EF entities and EF, work directly with EF. If you want to decouple the rest of the app from persistence details (note I've said persistence, not rdbms) use Repository properly. But don't kid yourself you're using the Repository pattern just because you have a class named repository. You should know exactly why are you using a pattern and what benefits it brings to your situation. It's not best practice if you don't understand why.

MVC db context overuse?

I have added a database repository layer to my MVC application which does the CRUD. Sometimes my controllers need to call multiple db repositories and I do this by calling the db respitories I need. This in turn creates multiple db context objects. One for each repository. Should there be multiple db context objects or should I pass in a single db context to the repository object?
In your controller you should use one dbContext. Because When you try to update your model in db, you may get error. Because of different dbContext.
Check HERE
There should be only one, I highly recommend using Unit of Work pattern:
Here's a quick and simple example:
public interface IUoW : IDisposable
{
MyDbContext DbContext { get; set; }
void SaveChanges();
}
public class UoW : IUoW
{
public MyDbContext DbContext { get; set; }
public UoW()
{
DbContext = new MyDbContext();
}
public void SaveChanges()
{
DbContext.SaveChanges();
}
public void Dispose()
{
DbContext.Dispose();
}
}
You need to instantiate UoW once for each request and pass it to your repository:
public class MyRepository
{
private MyDbContext _context;
public MyRepository(IUoW uow)
{
_context = uow.MyDbContext;
}
// your crud methods
}
Of course it's just a very simple example of it and I've seen people implement this pattern in many different ways.

Why DbContext doesn't implement IDbContext interface?

Why there is no IDbContext interface in the Entity Framework? Wouldn't it be easier to test things if there was an existing interface with methods like SaveChanges() etc. from which you could derive your custom database context interface?
public interface ICustomDbContext : IDbContext
{
// add entity set properties to existing set of methods in IDbContext
IDbSet<SomeEntity> SomeEntities { get; }
}
I see this IDbContext:
See this link And then you make a new partial class for your Entities Context With That interface.
public partial class YourModelEntities : DbContext, IDbContext
EDITED:
I edited this post, This Works for me.
My Context
namespace dao
{
public interface ContextI : IDisposable
{
DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbSet Set(Type entityType);
int SaveChanges();
IEnumerable<DbEntityValidationResult> GetValidationErrors();
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity:class;
DbEntityEntry Entry(object entity);
string ConnectionString { get; set; }
bool AutoDetectChangedEnabled { get; set; }
void ExecuteSqlCommand(string p, params object[] o);
void ExecuteSqlCommand(string p);
}
}
YourModelEntities is your auto-generated partial class, and your need to create a new partial class with the same name, then add your new context interface, for this example is ContextI
NOTE: The interface hasn't implement all methods, because the methods are implemented in your auto-generate code.
namespace dao
{
public partial class YourModelEntities :DbContext, ContextI
{
public string ConnectionString
{
get
{
return this.Database.Connection.ConnectionString;
}
set
{
this.Database.Connection.ConnectionString = value;
}
}
bool AutoDetectChangedEnabled
{
get
{
return true;
}
set
{
throw new NotImplementedException();
}
}
public void ExecuteSqlCommand(string p,params object[] os)
{
this.Database.ExecuteSqlCommand(p, os);
}
public void ExecuteSqlCommand(string p)
{
this.Database.ExecuteSqlCommand(p);
}
bool ContextI.AutoDetectChangedEnabled
{
get
{
return this.Configuration.AutoDetectChangesEnabled;
}
set
{
this.Configuration.AutoDetectChangesEnabled = value;
}
}
}
}
I was thinking also about that, I assume you are going to use it for mocking DbContext. I find no reason for that, except that you will need to implement your own DbSet manually in your anyway for your mocked class (so will need to rewrite your own interface anyway).
Just create a mock DbContext extending your production DbContext overriding the methods that complicate testing. That way, any changes to the production DbContext are automatically reflected in the tests, save for the overridden methods. For any other classes that deal with persistence and take the DbContext just extend them as well passing in the extended mock DbContext.
namespace Test.Mocks
{
public sealed class MockDatabaseContext : MainProject.Persistence.Database.DatabaseContext
{
public MockDatabaseContext(ConfigurationWrapper config) : base(config)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var dbPath = "test.db";
optionsBuilder.UseSqlite($"Filename={dbPath}");
}
}
}
namespace Test.Mocks
{
public class MockInventoryFacade : InventoryFacade
{
public MockInventoryFacade(MockDatabaseContext databaseContext) : base(databaseContext)
{
}
}
}
There is no IDbContext because it would be useless, the only implementation of it would be the DbContext.
EF team is also going this way with IDbSet if you look at this design meeting note
For me, the real problem with EF when it comes to unit testing is the DbConnection in the DbContext, fortunately there is Effort a nice project on codeplex that starts to fill this.
Effort is a powerful tool that enables a convenient way to create automated tests for Entity Framework based applications.
It is basically an ADO.NET provider that executes all the data operations on a lightweight in-process main memory database instead of a traditional external database. It provides some intuitive helper methods too that make really easy to use this provider with existing ObjectContext or DbContext classes. A simple addition to existing code might be enough to create data driven tests that can run without the presence of the external database.
With this, you can leave your DbContext and DbSet as is and do your unit tests easily.
The only drawback with this is the difference between Linq providers where some unit tests may pass with effort and not with the real backend.
UPDATE with EF7
I still maintain that IDbContext would be useless and the problem comes from the DbConnection.
EF7 will not have an IDbContext either, in order to do unit testing they are now giving an in memory provider.
You can see Rowan Miller doing a demo here: Modern Data Applications with Entity Framework 7

What are the major limitations of EF4?

I am trying to decide on an ORM tool for my project, and I am thinking about EF4.
What are the major (if any) annoyances/limitations with this product? Also, does it support caching?
Thanks
This is a good place to start. Granted he's one of the main contributors of NHibernate so that particular post may seem a little bit biased, but there are some good links and arguments in the comments.
And looks like someone asked a very similar question on SO a few months back.
The inability to use private backing fields for lazy loading collections. For example take this class:
public class Account
{
private IList<Customer> _customers = new List<Customer>();
public IEnumerable<Customer> Customers
{
get { return _customers ; }
}
public void AddCustomer(Customer customer)
{
//Perform some biz rules
_customers.Add(customer)
}
}
Access to the customers collection is restricted by using an IEnumerable collection and having a AddCustomer / RemoveCustomer methods on the class. Typically you want to do some business checking before adding or removing a new customer.
The current version of EF requires lazy loading collection types to be ICollection (or any type that implements ICollection). So the above class now would look like:
public class Account
{
private IList<Customer> _customers = new List<Customer>();
public virtual ICollection<Customer> Customers
{
get { return _customers ; }
}
public void AddCustomer(Customer customer)
{
//Perform some biz rules
_customers.Add(customer)
}
}
Using a public ICollection Customers completely destroys good OO design principals as consumers could directly access by calling the Add Operation on ICollection.
Account acc = new Account();
acc.Customers.Add(new Customer()); //Bad code
The original intention of the domain class was to use the public add method:
Account acc = new Account();
acc.AddCustomer(new Customer());
NHibernate can handle this scenario through configuration. I would very much like to see this scenario supported in the EF.
Note however there is a workaround for the this limitation by declaring the the backing field as protected and map it through configuration:
public class Account
{
protected virtual ICollection<Customer> _customers = new Collection<Customer>();
public IEnumerable<Customer> Customers
{
get { return _customers ; }
}
public void AddCustomer(Customer customer)
{
//Perform some biz rules
_customers.Add(customer)
}
}
But this won't work if your application has a layered architecture (i.e your domain model is separated from EF configuration classes) because protected types are not accessible to external classes.
In order for this to work requires the EF classes to be in the same assembly as your domain models!
Lazing loading collections require a public or protected type that implements ICollection.