I am not grasping something when creating my repository pattern with EF Code First. If I want to abstract out EF I would have to make my repository be of type IObjectContextAdapter, no? That is what DbContext implements. If I later switch to use something like NHibernate or some other 3rd party ORM, it may not implement IObjectContextAdapter.
Is my only solution to create a wrapper that wraps the ORM and does return an implementation of IObjectContextAdapter? If so, what is the point?
I'm not sure you have to implement IObjectContextAdapter when creating a repository pattern with EF. The main difference between using EF or something like NHibernate will be how to wrap either the DbContext or the ISession respectively.
Here is a sketch of how an EF code-first repository could be written:
public interface IRepository<TEntity>
{
void Save();
}
public class Repository<TEntity> : IRepository<TEntity>
{
private readonly IDbSet<TEntity> entitySet;
public Repository(DbContext context)
{
this.entitySet = context.Set<TEntity>();
}
public void Save()
{
return this.entitySet.SaveChanges();
}
}
This allows the actual DbContext to be injected.
Related
I am using ef core and I am trying to implement the repository pattern as part of best practices. But I am we bit confused on the context normally I would create the context in the and inject
HomeController(WarehouseDBContext _context)
I have created my unitOfWork Class as suggested by the docs here
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application#creating-the-unit-of-work-class
However I am tad confused. It's expecting options here which is normally handled on the controller.
My UnitOfWork class
public class WarehouseUnitOfWork : IDisposable
{
private WarehouseDBContext context = new WarehouseDBContext();
private WarehouseRepository<StockItem> stockRepository;
public WarehouseRepository<StockItem> StockRepoistry
{
get
{
if (this.stockRepository == null)
{
this.stockRepository = new WarehouseRepository<StockItem>(context);
}
return stockRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
But here it is complain that it expect options which would I presume contain the connection string. I am trying to decouple my code from EF so that If I want to upgrade in the future will be easier. My WareshouseDBContext is describe below
As you can see it is expecting options. What should I pass through here?
namespace WareHouseDal.Dal {
public class WarehouseDBContext : IdentityDbContext<ApplicationUser> {
public WarehouseDBContext(DbContextOptions<WarehouseDBContext> options)
: base(options) {
}
public DbSet<WarehouseCrm> Warehouse { get; set; }
public DbSet<Company> Companies { get; set; }
}
}
When I used to create my context before I just used the singleton pattern of
private readonly WarehouseDBContext _context;
Is their something else I need to do to allow it to accept the creation of the context on the unit of work level.
Error being given is
You shouldn't create a DbContext manually. Why not injecting the DbContext in your UOW class? Then the DI will manage the life cycle of the db context. To be honest I am not a fan of adding a UOW wrapper around EF which already implements the UOW pattern.
I would recommend you to see both talks, it will change the way you structure apps forever:
https://www.youtube.com/watch?v=5OtUm1BLmG0&ab_channel=NDCConferences
https://www.youtube.com/watch?v=5kOzZz2vj2o&t=3s&ab_channel=NDCConferences
Another amazing talk about EF Core details: https://www.youtube.com/watch?v=zySHbwl5IeU&ab_channel=NDCConferences
If you want to stick with Repository pattern, please check Ardalis repository with a clear example: https://github.com/ardalis/CleanArchitecture
I agree Ardalis repository is a great tutorial/example, in case if anyone want a lite solution to implement the Repository and Unit of Work Patterns in EF 5/EF 6.
you may check out the below one, I tested it would work in EF Core 6
https://pradeepl.com/blog/repository-and-unit-of-work-pattern-asp-net-core-3-1/
I'm making an app that try to follow the Clean architecture guideline. The app use JavaFX as UI. JavaFX is make to use the MVC architecture. Is there a way to use both in conjunction like this?
My problem is i can't find a way to have a Controller and a Presenter that interact with the FXML file.
Currently i have this :
An FXML file that declare a controller with fx:controller attribute
A controller That handle event and called a usecase
A usecase like this:
public class SomeUseCase implements UseCase<Observable<String>> {
private SomeRepository repository;
public SomeUseCase(SomeRepository repository) {
repository = repository;
}
#Override
public void execute(Request request, Presenter presenter) {
SomeUseCaseRequest req = (SomeUseCaseRequest) request;
// I skip mapper that translate from request to entity and entity to repository
// And vice-versa for the respponse for clarity
presenter.render(this.repository.fetch(req.someParam));
}
}
I have 2 model classes:
Customer.cs with name and Id
Movies.cs with name and Id
I tried to run enable-migrations, but I got this error:
No context type was found in the assembly WebApplication2'.
Then I saw some answers on websites and people told to make a DBContext class. I do not have any DBContext class as I just made a new MVC project.
So, I tried to make a DbContext class of my own as follows:
{
public class MyDBContext:DbContext
{
public void MyDbContext()
{
}
}
}
Then I was able to run enable-migrtaions command and Migration folder was created with configuration.cs as follows:
internal sealed class Configuration : DbMigrationsConfiguration<WebApplication2.Models.MyDBContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(WebApplication2.Models.MyDBContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
}
}
}
Now when I run the add-migration Initialmodel the Up() and Down() methods are empty and there are no Identity tables.
Please help !
First off I suggest you refer to creating a new MVC project using Entity Framework. There are a lot of tutorials but here's the Microsoft one which is accurate and pretty complete:
Get Started with Entity Framework 6 Code First using MVC 5
It also includes a section on Migrations, however you don't need Migrations until you have a database and a model that's changing.
I would suggest backing out your Migrations until we're ready for them. Rick Strahl has a good article on how to back them out and get back to a clean state:
Resetting Entity Framework Migrations to a clean State
Finally, your DbContext class has to have a DbSet. A DbSet class is an entity set that can be used for create, read, update, and delete operations. With your DbContext class as it is, Entity Framework has no idea what to do or map.
Change your DbContext class to something like this:
{
public class MyDBContext:DbContext
{
public void MyDbContext()
{
}
public virtual DbSet<Movie> Movies {get; set;}
public virtual DbSet<Customer> Customers {get; set;}
}
This will allow you (say in a Controller) to do something like this to add a new Customer to the database:
var customer = new Customer { name = "John Smith" };
using(var context = new MyDbContext())
{
context.Customers.Add(customer); // adds the customer to the DbSet in memory
context.SaveChanges(); // commits the changes to the database
}
NOTE: I don't recommend creating a DbContext this way in a controller, in the first link on using EF6 with MVC 5 there are better ways.
Hope that helps.
We are using EF with DB first, and we are not planning to create Repository classes per table. Instead, we will have repository classes representing modules, which internally might interact with multiple tables.
The code which I have started writing is something like this:
public class ModuleRepository
{
public void GetModules()
{
using (IUnitOfWork uow = new UnitOfWork())
{
//Get the specific DBSet
var dbTable = uow.GetDbSet<Customer>();
var dbTable1 = uow.GetDbSet<Supplier>();
//do whatever you want to do.
//call save changes to commit
uow.SaveChanges();
}
}
}
class UnitOfWork: IUnitOfWork
{
private DbContext _context;
public UnitOfWork()
{
_context = new DbContext("");
}
public void Dispose()
{
throw new NotImplementedException();
}
public void SaveChanges()
{
throw new NotImplementedException();
}
public DbSet<T> GetDbSet<T>() where T:class
{
DbSet<T> entities = _context.Set<T>();
return entities;
}
}
public interface IUnitOfWork: IDisposable
{
void SaveChanges();
DbSet<T> GetDbSet<T>() where T : class;
}
In SaveChanges I will have the _context.SaveChanges() to commit the changes to the DB.
This is I guess one way to do this.
Another possible way could be:
create a generic base repository class. Each module repository will have a list of these repository classes.
uow class
UOW Manager -> will pass list of base repositories to say a method Setup. This UOW Manager will create a UOW with a context, and this UOW will be passed to each repository - effectively all repository having the same context.
I think code wise it will work, though not sure which one is the right approach or there could be some better approach.
Also in any of these two scenarios, how to achieve unit testing? Any ideas around this?
I'm using Unity.MVC for DI in my ASP.NET MVC 4.6 app. I have a service interface passed into the controller and that's working great. Now I want to pass in an interface to the EF context to the service but I'm not sure how to do this. I've read EF has this IObjectContextAdapter that I could pass into my service ctor and that works, but I need to then query the actual tables on inside my service from this context but because it's an IObjectContextAdapter it doesn't know my tables. How do I do this?
public class ContactService : IContactService
{
//private ContactsEntities context;
private IObjectContextAdapter context;
// test ctor
public ContactService(IObjectContextAdapter ctx)
{
context = ctx;
}
// prod ctor
public ContactService()
{
context = new ContactsEntities();
}
List<Contact> GetAllContacts()
{
return (from c in context.ObjectContext.?? // I need to query the Contacts table that would be attached to the actual context I pass in but still keep the decoupling from using an Interface passed into the ctor
}
}
The IObjectContextAdapter is the type of ObjectContext property of DbContext.
You should subclass DbContext e.g. ContactsDatabaseContext
public class ContactsDatabaseContext : DbContext, IContactsDatabaseContext
{
// ...
}
And then just register your ContactsDatabaseContext with your IoC container. Something like this:
container.RegisterType<IContactsDatabaseContext, ContactsDatabaseContext>();
Your ContactsDatabaseContext class and IContactsDatabaseContext interface should have properties of type DbSet<T> that refer to your tables e.g.:
IDbSet<BrandDb> Users { get; set; }
UPDATE:
Since you are using a generated file, then do this:
public partial class ContactsDatabaseContext : IContactsDatabaseContext
{
// Expose the DbSets you want to use in your services
}