I'm using CodeFirst EF6 and I'd like to place all related "queries" into a single class.
Let's say I have a
DbSet<Car> Cars;
in my DbContext.
I tried to create a new class with my concrete DbSet as base class:
public class CarRepository : DbSet<Car>
in which I'd locate all car related operations.
When I replace DbSet with CarRepository in my DbContext class it won't get filled.
I then tried to derive from IDbSet but I'm not sure how to implement all needed methods.
Is there another way to achieve this goal without using an extension class?
You can simply create your own single class(your repository) and put your methods like this.
public class Repository<TEntity> where TEntity : class
{
private DbContext context;
private DbSet<TEntity> dbSet;
public Repository(DbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
}
Related
What is the best way to update data in EF core in asp.net core application?
I can do it like this
public class Repository<T> : IRepository<T> where T : BaseEntity
{
private DbContext context;
private DbSet<T> entities;
public Repository(DbContext context)
{
this.context = context;
this.entities = context.Set<T>();
}
public void Update(T entity)
{
T exist = this.entities.Find(entity.Id);
this.context.Entry(exist).CurrentValues.SetValues(entity);
this.context.SaveChanges();
}
}
Or i can use the Update() method of DbSet. But to use it I need to set QueryTrackingBehavior to "no-tracking" firstly, something like this:
public class Repository<T> : IRepository<T> where T : BaseEntity
{
private DbContext context;
private DbSet<T> entities;
public Repository(DbContext context)
{
this.context = context;
this.context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
this.entities = context.Set<T>();
}
public void Update(T entity)
{
this.entities.Update(entity);
this.context.SaveChanges();
}
}
Is it a good idea? What option is better and why?
According to EF Core documentaion
SetValues will only mark as modified the properties that have different values to those in the tracked entity. This means that when the update is sent, only those columns that have actually changed will be updated. (And if nothing has changed, then no update will be sent at all.)
So I think your first approach (this.context.Entry(exist).CurrentValues.SetValues(entity);)
should be the best for updating entity!
Hello I use entity framework with a unit of work pattern and I would like to know if in my application layer I should work directly with entities generated by entity framework or recreate POCO objects in my application layer and map my POCO?
Because I would like my application layer not to make any reference to my entities, I would like for example to create another project in my solution that could map my entities to my poco in my application but I don't know if this is a good practice and especially I don't know how to do it
Thank you in advance!
In my UnitOfWork I have used a generic repository pattern that uses the models generated by the EF directly. The IRepository<T> interface looks a bit like this:
public interface IRepository<T> where T : class
{
void Add(T entity);
T GetById(long Id);
//etc - all the stuff you probably have
}
I have implementation of the IRepository called Repository
public Repository<T> : IRepository<T>
{
public readonly Infomaster _dbContext;
public Repository(Infomaster dbContext)
{
_dbContext = dbContext;
}
public void Add(T entity)
{
_dbContext.Set<T>.Add(t);
}
}
The use of the set and the type allows me to access the dataset (dbSet) of that particular type which allows me to create a generic pattern. You can use specific classes but it's a lot more work.
This means in my UnitOfWork, I only need to do the following:
public class UnitOfWork : IUnitOfWork
{
//Db context
Infomaster _dbContext;
//User is a model from my EF
public IRepository<User> UserRepository { get; private set; }
public UnitOfWork()
{
_dbContext = new Infomaster();
UserRepository = new Repository<User>(_dbContext);
}
public int Commit()
{
return _dbContext.Save();
}
}
I find that is the best way and requires the use of the model classes, I am using a code first database but I have done with database first.
(from iPhone - can and will update from laptop)
I have no choice in creating a data first Entity Framework implementation. I want to extend the generated class to include a generic base class that I can call all the basic functions on. (I know how to update the t4 templates)
Update (add if not currently in DB), GetAll, Select (based on parameters) and Delete functions. I have found a few things that I think may work but they do not have fully qualified namespaces and I can't figure out where the information is stored.
Creating base class for Entities in Entity Framework - is one such which is basically a duplicate of my question but the answers are not complete.
What would be an example of this base class WITH the fully qualified namespace?
You can still use Code First even though you have a database. You can generate your model. Depends what you need, please see 2 different ways to approach the problem.
Generic repository
public abstract class BaseRepository<TEntity> where TEntity : class
{
protected DbContext context;
protected BaseRepository(MyDbContext context)
{
this.context = context;
}
public List<TEntity> GetAll()
{
// Set<TEntity> provides you an access to entity DbSet
// Just like if you call context.Users or context.[AnyTableName]
return context.Set<TEntity>().ToList();
}
}
Next you want to implement entity-specific repositories:
public class UserRepository : BaseRepository<User>
{
public UserRepository(MyDbContext context) : base(context)
{
}
}
Simple usage example:
using (var context = new MyDbContext())
{
var userRepository = new UserRepository(context);
var users = userRepository.GetAll();
}
Just put your generic methods in context
public class MyContext : DbContext
{
public DbSet<User> Users { get; set; }
// ... more DbSets
public List<TEntity> GetAll<TEntity>() where TEntity : class
{
return Set<TEntity>().ToList();
}
// For entities that implement INamedEntity interface
// with property Name.
public TNamedEntity FindByName<TNamedEntity>(string name)
where TNamedEntity : INamedEntity, class
{
return Set<TNamedEntity>()
.FirstOrDefault(entity => entity.Name == name);
}
}
I use nuget package EntityFramework. DbContext and DbSet comes from System.Data.Entity namespace.
Hope it's enough for you to get started and implement all the methods that you need.
I am currently implementing EF6 to replace the ADO connection that currently exists.
I have read articles on why I should/shouldn't use the Repository pattern.
However I'm still not sure how to correctly call the repository pattern.
My project is layered as:
Presentation
Business Layer
Business Objects
Data Access Layer
Web Services
In the DAL I add my EF6 connection to my DB.
I created a IRepository and Repository classes.
Should the Business Layer be the one to call the Repository class?
If so I'm missing the connection here on how to call it.
Repository class:
public class MyRepository<T> : IRepository<T> where T : class
{
protected DbSet<T> DbSet;
protected DbContext _context;
public MyRepository(DbContext dataContext)
{
_context = dataContext;
DbSet = dataContext.Set<T>();
}
#region IRepository
public int Save()
{
return _context.SaveChanges();
}
public void Insert(T entity)
{
DbSet.Add(entity);
}
public void Delete(T entity)
{
DbSet.Remove(entity);
}
public IQueryable<T> SearchFor(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
return DbSet.Where(predicate);
}
public IQueryable<T> GetAll()
{
return DbSet;
}
public T GetById(int id)
{
return DbSet.Find(id);
}
#endregion
}
My goal is to have MyRepository handle the 6 or so tables that I added in EF.
Where I am missing is how to implement this class in my business access layer.
I get the error
'MyEFConn' is a 'type' but is used like a 'variable'
My attempt at implementing it is:
MyRepository<"table from EF"> users = new MyRepository<"table from EF">(MyEFConn);
Which MyEFConn is my DbContext class..
public partial class MyEFConn: DbContext
I get the error 'MyEFConn' is a 'type' but is used like a 'variable'
This is because the constructor for MyRepository expects to be passed an instance of a DbContext. In your case that would be an instance of MyEFConn.
Ex:
MyEfConn context = new MyEfConn();
MyRepository<MyUsers> users = new MyRepository<MyUsers>(context);
I am working on ASP.NET MVC 4 project from scratch. I decided to start with the data access layer using Entity Framework 5 and Code First workflow. The company where I used to work was using very good implementation (in my opinion) of the Repository pattern including Repositories, Services, Abstract Factory for the Repositories and the Services and Unity for DI. I tried to redo it but it's just too complicated for me and will cost me a lot of time to replicate what I've been using there, so I decided to do some research and go with something lighter.
So I decided to use GenericRepository and UnitOfWork - far from what was the initial plan, but that was the implementation that was showing in most of my searches. So I did a very basic implementation (Just to the point where I'm sure I know what's going on, maybe even below my abilities to comprehend) and actually I think for this exact project it may be just enough but what I want is to be able to call additional custom methods on the different entities.
I think this gets a lot from the idea of generic repository, but if I try to go with some other implementation it's getting exponentially harder, so I wonder if there's a way to add this to my implementation without hurting too much the idea behind the generic Repository.
What I have now is the GenericRepository class :
public class GenericRepository<TEntity> where TEntity : class
{
internal DBContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(DBContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get()
{
IQueryable<TEntity> query = dbSet;
return query.ToList();
}
//just the standard implementation
and my UnitOfWork class :
public class UnitOfWork : IDisposable
{
private DBContext context = new DBContext();
private CustomerRepository customerRepository;
public CustomerRepository CustomerRepository
{
get
{
if (this.customerRepository == null)
this.customerRepository = new CustomerRepository(context);
return customerRepository;
}
}
private GenericRepository<Order> orderRepository;
public GenericRepository<Order> orderRepository
{
get
{
So as you may see my Order entity is using the GenericRepository but I made a test class CustomerRepository to use for my Customer entity.
For now this class CustomerRepository looks like this :
public class CustomerRepository : GenericRepository<Customer>
{
public CustomerRepository(DBContext context) : base(context) { }
}
and the idea is to add the methods that are explicitly for the Customer entity here. I'm not sure if this is correct, especially the way I call the constructor. However, what is the natural way to add those specific methods for the different entities? I don't mind to even take a step back to implement it better but I don't want to rush it cause I tried and at the moment the whole concept is too complicated for me and I want to be sure that I understand the things that I use in my code.
I think you are on the right track. Here is the generic repository that I use:
public interface IRepository<TEntity>
where TEntity : class
{
IQueryable<TEntity> GetAll();
IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate);
TEntity GetById(long id);
void Add(TEntity entity);
void Update(TEntity entity);
void Delete(TEntity entity);
}
public class Repository<TEntity> : IRepository<TEntity>
where TEntity : class
{
protected readonly DbEntities Context;
protected readonly DbSet<TEntity> Set;
public Repository()
{
Context = new DbEntities();
Set = Context.Set<TEntity>();
}
public virtual IQueryable<TEntity> GetAll()
{
return Set;
}
public virtual IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate)
{
return Set.Where(predicate);
}
public virtual TEntity GetById(long id)
{
return Set.Find(id);
}
public virtual void Add(TEntity entity)
{
Set.Add(entity);
Context.SaveChanges();
}
public virtual void Update(TEntity entity)
{
Set.Attach(entity);
Context.Entry(entity).State = EntityState.Modified;
Context.SaveChanges();
}
public virtual void Delete(TEntity entity)
{
Set.Remove(entity);
Context.SaveChanges();
}
}
// And assuming User is a data object with an Id property:
public interface IUserSpecificRepository
{
List<User> GetById(long id)
}
public class UserSpecificRepository : IUserSpecificRepository, Repository<User>
{
public virtual List<User> GetById(long id)
{
return GetBy(x => x.Id = id).ToList();
}
}
Notice that GetAll() and GetBy() return a queryable. This is to allow control of when the query expression gets converted to SQL and hits the database. Usually a call to ToList() will cause this. You can then inherit from this and any custom methods can make use of these two starter methods.
Also, As a general rule of thumb, you should never do a GetAll().ToList() like you have now. If you have a zilion records you will run into problems. It is also a performance issue if you are filtering down to a few records. GetAll().ToList().Where(x => x.Id = 1) basically gets all zillion records from the db into memory, then filters it down to one. You should instead do this GetAll().Where(x => x.Id = 1).ToList().
Hope this helps you along!