I am playing around with making a nhibernate generic repo but I am unsure how to make a method to return an entity back by ID
public class NhibernateRepo : INhibernateRepo
{
private readonly ISession session;
public NhibernateRepo(ISession session)
{
this.session = session;
}
public void Create<T>(T entity)
{
session.Save(entity);
}
public void CreateOrUpdate<T>(T entity)
{
session.SaveOrUpdate(entity);
}
public void Delete<T>(T entity)
{
session.Delete(entity);
}
public void Update<T>(T entity)
{
session.Update(entity);
}
public T Get<T>(object id)
{
return session.Get<T>(id);
}
public T Load<T>(object id)
{
return session.Load<T>(id);
}
public void ReadOnly(object entity, bool readOnly = true)
{
session.SetReadOnly(entity, readOnly);
}
public void Evict(object entity)
{
session.Evict(entity);
}
public object Merge(object entity)
{
return session.Merge(entity);
}
public IEnumerable<T> FindAll<T>()
{
return session.Query<T>();
}
}
You can define this method in the repository interface:
interface IRepository<TEntity, TId> where TEntity : class {
TEntity FindById(TId id);
...
}
And following in repository implementation:
class Repository<TEntity, TId> : IRepository<TEntity, TId> where TEntity : class{
public TEntity FindById(TId id) {
return _session.Get<TEntity>(id);
}
}
As a side note, generic repository interface is sometimes considered to be a bad practice from Domain Driven Design perspective.
Related
I am developing a project in layered architecture to improve myself.Now let me show you my layers.
public class EfEntityRepositoryBase<TEntity, TContext> : IEntityRepository<TEntity>
where TEntity : class, IEntity, new()
where TContext : DbContext, new()
{
public void Add(TEntity entity)
{
using (var context = new TContext())
{
var addedEntity = context.Entry(entity);
addedEntity.State = EntityState.Added;
context.SaveChanges();
}
}
public async void AddAsync(TEntity entity)
{
using (var context = new TContext())
{
context.Add(entity);
await context.SaveChangesAsync();
}
}
public void Delete(TEntity entity)
{
using (var context = new TContext())
{
var removedEntity = context.Entry(entity);
removedEntity.State = EntityState.Deleted;
context.SaveChanges();
}
}
public TEntity Get(Expression<Func<TEntity, bool>> filter = null)
{
using (var context = new TContext())
{
return context.Set<TEntity>().SingleOrDefault(filter);
}
}
public List<TEntity> GetList(Expression<Func<TEntity, bool>> filter = null)
{
using (var context = new TContext())
{
return filter == null
? context.Set<TEntity>().ToList()
: context.Set<TEntity>().Where(filter).ToList();
}
}
public void Update(TEntity entity)
{
using (var context = new TContext())
{
var updatedEntity = context.Entry(entity);
updatedEntity.State = EntityState.Modified;
context.SaveChanges();
}
}
}
This is my data access layer.
public class IProductManager : IProductService
{
private IProductDal _productDal;
public IProductManager(IProductDal productDal)
{
_productDal = productDal;
}
public void Add(Product product)
{
_productDal.Add(product);
}
public void AddAsync(Product product)
{
_productDal.AddAsync(product);
}
public void Delete(int productId)
{
_productDal.Delete(new Product { ProductId = productId });
}
public List<Product> GetAll()
{
return _productDal.GetList();
}
public List<Product> GetByCategoryId(int categoryId)
{
return _productDal.GetList(p => p.CategoryId == categoryId || categoryId== 0);
}
public Product GetById(int productId)
{
return _productDal.Get(p => p.ProductId == productId);
}
public void Update(Product product)
{
_productDal.Update(product);
}
}
This is my business layer.
When I try to write generic, some things are missing, so I don't understand much.
Now I want to ask, how should I write the following code, because I'm new, I couldn't do it.
List<Product> products = context.Products.Include(x => x.Photos).ToList();
I can post it anywhere you want.
If I understood you correctly, you want to change
List<Product> products = context.Products.Include(x => x.Photos).ToList()
to something like:
List<T> entities = context.Set<T>().Include(x => x.Photos).ToList()
You can not. Let's say you want to use this generic class for your Category model and your Category model does not have Photos property.
I would suggest to make a generic Repository class for all CRUD operations
public interface IBaseRepository<T> where T : class
{
Task AddAsync(T entity);
void Delete(T entity);
void Update(T entity);
Task<IEnumerable<T>> GetAllAsync();
Task<T> FindAsync(Expression<Func<T, bool>> expression);
}
And implementing:
public class BaseRepository<T> : IBaseRepository<T> where T : class
{
protected readonly AppDbContext _context;
private DbSet<T> _dbSet;
public DbSet<T> DbSet => _dbSet ??= _context.Set<T>();
public BaseRepository(AppDbContext context)
{
_context = context;
}
public async Task AddAsync(T entity)
{
await DbSet.AddAsync(entity);
}
public void Delete(T entity)
{
DbSet.Remove(entity);
}
public void Update(T entity)
{
DbSet.Update(entity);
}
// here we made vitrual, this gaves us opportunity to override this method
public virtual async Task<IEnumerable<T>> GetAllAsync()
{
return await DbSet.ToListAsync();
}
public virtual async Task<T> FindAsync(Expression<Func<T, bool>> expression)
{
return await DbSet.Where(expression).FirstOrDefaultAsync();
}
}
Your Product Repository:
public class ProductRepository : BaseRepository<Product>
{
public ProductRepository(AppDbContext context) : base(context)
{
}
public async override Task<IEnumerable<Product>> GetAllAsync()
{
return await DbSet.Include(p => p.Photos).ToListAsync();
}
}
I'd like to implement a generic repository pattern using Entity Framework (I know there are many controversial opinions about repositories, but still this is what I need).
The interface I'd like it to have is as follows:
public interface IRepository
{
IQueryable<TEntity> Query<TEntity>()
where TEntity: Entity;
void Save<TEntity>(TEntity entity)
where TEntity : Entity;
void Delete<TEntity>(TEntity entity)
where TEntity : Entity;
}
Entity is a base class that just has an int ID property.
And to use it like this:
IRepository repository = ... // get repository (connects to DB)
int userId = GetCurrentUserId();
if (!repository.Query<User>().Any(u => u.Id == userId)) // performs SELECT query
{ /*return error*/ }
var newOrder = new Order { UserId = userId, Status = "New" }
repository.Save(newOrder); // performs INSERT query
...
newOrder.Status = "Completed";
repository.Save(newOrder); // performs UPDATE query
I'd like to avoid UnitOwWork and just commit all object changes to the DB once Save() or Delete() is called. What I want to do looks really simple, but I haven't found any examples of how to do it using EntityFramework.The closest example I could find is this answer, but it uses UnitOwWork and repository-per-entity, which is more complicated than what I need to do.
1-Create One Interface
interface IMain<T> where T : class
{
List<T> GetAll();
T GetById(int id);
void Add(T entity);
void Edit(T entity);
void Del(int id);
int Savechange();
}
2-Create One Class
public class Main<T> : IMain<T> where T : class
{
public DataContext db;
public void Add(T entity)
{
db.Set<T>().Add(entity);
}
public void Del(int id)
{
var q = GetById(id);
db.Set<T>().Remove(q);
}
public void Edit(T entity)
{
db.Entry<T>(entity).State = EntityState.Modified;
}
public List<T> GetAll()
{
return db.Set<T>().Select(a=>a).ToList();
}
public T GetById(int id)
{
return db.Set<T>().Find(id);
}
public int Savechange()
{
return db.SaveChanges();
}
}
3-Create One Repository With Name YourTable ForExample Student
public class Student : Main<Tbl_Student>
{
public Student()
{
db = new DataContext();
}
}
4-To Your Action Write This Code
Student student=new Student();
student.Del(3);
int a = student.Savechange();
You can do that with expression keyword;
public interface IRepository<TEntity> where TEntity : Entity
{
IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> predicate);
void Save(TEntity entity);
void Delete(TEntity entity);
}
public abstract class EfRepository<T> : IRepository<T> where T : Entity
{
private readonly DbContext _dbContext;
protected readonly DbSet<T> _dbSet;
public EfRepository(YourDbContextContext dbContext)
{
_dbContext = dbContext;
_dbSet = dbContext.Set<T>();
}
public void Delete(T entity)
{
if (entity == null) return;
else
{
DbEntityEntry dbEntityEntry = _dbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Deleted)
{
dbEntityEntry.State = EntityState.Deleted;
}
else
{
_dbSet.Attach(entity);
_dbSet.Remove(entity);
_dbContext.SaveChanges();
}
}
}
public IQueryable<T> Query(Expression<Func<T, bool>> predicate)
{
return _dbSet.Where(predicate);
}
public void Save(T entity)
{
if (entity.Id > 0)
{
_dbSet.Attach(entity);
_dbContext.Entry(entity).State = EntityState.Modified;
_dbContext.SaveChanges();
}
else
{
_dbSet.Add(entity);
_dbContext.SaveChanges();
}
}
}
public class Entity
{
public int Id { get; set; }
}
Then create your repositories;
public interface IUserRepository : IRepository<User>
{
//Also you can add here another methods according to your needs
}
public class UserRepository : EfRepository<User>,IUserRepository
{
public UserRepository(YourDbContext yourDbContext) : base(yourDbContext)
{
}
}
Then use it;
IUserRepository _userRepository => Getit
//If there are entities according to your conditions, this will return them, then use it
_userRepository.Query(u => u.Id == userId);
I used to use it but as many developers have said it will add more complexity to your code and can cause problems:
Code for my interface IRepositoryBase:
public interface IRepositoryBase<TEntity> where TEntity : class
{
void Add(TEntity objModel);
void AddRange(IEnumerable<TEntity> objModel);
TEntity GetId(int id);
Task<TEntity> GetIdAsync(int id);
TEntity Get(Expression<Func<TEntity, bool>> predicate);
Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate);
IEnumerable<TEntity> GetList(Expression<Func<TEntity, bool>> predicate);
Task<IEnumerable<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate);
IEnumerable<TEntity> GetAll();
Task<IEnumerable<TEntity>> GetAllAsync();
int Count();
Task<int> CountAsync();
void Update(TEntity objModel);
void Remove(TEntity objModel);
void Dispose();
}
Code for implementatation of my interface on the repsoitory RepositoryBase:
public class RepositoryBase<TEntity> : IRepositoryBase<TEntity> where TEntity : class
{
#region Fields
protected readonly EntityContext _context = new EntityContext();
#endregion
#region Methods
public void Add(TEntity objModel)
{
_context.Set<TEntity>().Add(objModel);
_context.SaveChanges();
}
public void AddRange(IEnumerable<TEntity> objModel)
{
_context.Set<TEntity>().AddRange(objModel);
_context.SaveChanges();
}
public TEntity GetId(int id)
{
return _context.Set<TEntity>().Find(id);
}
public async Task<TEntity> GetIdAsync(int id)
{
return await _context.Set<TEntity>().FindAsync(id);
}
public TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>().FirstOrDefault(predicate);
}
public async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate)
{
return await _context.Set<TEntity>().FirstOrDefaultAsync(predicate);
}
public IEnumerable<TEntity> GetList(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>().Where<TEntity>(predicate).ToList();
}
public async Task<IEnumerable<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate)
{
return await Task.Run(() =>
_context.Set<TEntity>().Where<TEntity>(predicate));
}
public IEnumerable<TEntity> GetAll()
{
return _context.Set<TEntity>().ToList();
}
public async Task<IEnumerable<TEntity>> GetAllAsync()
{
return await Task.Run(() => _context.Set<TEntity>());
}
public int Count()
{
return _context.Set<TEntity>().Count();
}
public async Task<int> CountAsync()
{
return await _context.Set<TEntity>().CountAsync();
}
public void Update(TEntity objModel)
{
_context.Entry(objModel).State = EntityState.Modified;
_context.SaveChanges();
}
public void Remove(TEntity objModel)
{
_context.Set<TEntity>().Remove(objModel);
_context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
#endregion
}
My entities interface:
public interface IMyEntityRepository : IRepositoryBase<MyEntity>
{
//here you can place other implementations your repository doesn't have
}
public class MyEntityRepository : RepositoryBase<MyEntity>, IMyEntityRepository
{
}
How to call it (I was using dependency injection):
public class MyServiceOrController
{
#region Fields
private readonly IMyEntityRepository _myEntityRepository;
#endregion
#region Constructors
public MyServiceOrController(IMyEntityRepository myEntityRepository)
{
_myEntityRepository = myEntityRepository;
}
#endregion
#region Methods
public IList<MyEntity> TestGetAll()
{
return _myEntityRepository.GetAll();
}
#endregion
}
I have a simple generic repository.
In this Repository, I have a generic DBContext and thats means its not specific to my appliktion.
The generic DbContext are still able to access my DBcontexts Entites, such
Context.Set<TEntity>().Add(entity)
Do the method Set() here geting reference to my webapplikationens DBContext, or what is happening ?
Full Code:
public interface IRepository<TEntity> where TEntity : class
{
TEntity Get(int id);
void Add(TEntity entity);
}
...
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly DbContext Context;
public Repository(DbContext context)
{
Context = context;
}
public TEntity Get(int id)
{
// Here we are working with a DbContext, not PlutoContext. So we don't have DbSets
// such as Courses or Authors, and we need to use the generic Set() method to access them.
//Returns a non-generic DbSet instance for access to entities of the given type in the context and the underlying store .
return Context.Set<TEntity>().Find(id);
}
public void Add(TEntity entity)
{
Context.Set<TEntity>().Add(entity);
}
}
.................................
public interface IAuthorRepository : IRepository<Author>
{
Author GetAuthorWithCourses(int id);
}
..
public class AuthorRepository : Repository<Author>, IAuthorRepository
{
public AuthorRepository(PlutoContext context) : base(context)
{
}
public Author GetAuthorWithCourses(int id)
{
return PlutoContext.Authors.Include(a => a.Courses).SingleOrDefault(a => a.Id == id);
}
public PlutoContext PlutoContext
{
get { return Context as PlutoContext; }
}
}
..
public interface IUnitOfWork : IDisposable
{
IAuthorRepository Authors { get; }
int Complete();
}
...
public class UnitOfWork : IUnitOfWork
{
private readonly PlutoContext _context;
public UnitOfWork(PlutoContext context)
{
_context = context;
Authors = new AuthorRepository(_context);
}
public IAuthorRepository Authors { get; private set; }
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
...
public class Repository<Entity> : IRepository<Entity> where Entity : class
{
protected readonly DbContext Context;
public Repository(DbContext context)
{
Context = context;
}
public void Add(Entity entity)
{
Context.Set<TEntity>().Add(entity);
}
}
The argument DbContext context is just a compile-time type, the actual type of the parameter isn't changed.
The code below seems to work using this:
var unitOfWorkProvider = new PetaPocoUnitOfWorkProvider();
var repository = new FakeRepository();
var fake = new Fake
{
// etc.
};
using (var uow = unitOfWorkProvider.GetUnitOfWork("BlaConnectionString"))
{
repository.Insert(uow, fake);
uow.Commit();
}
which may eventually move into a service layer. I would appreciate any feedback to improve this code.
public interface IUnitOfWork : IDisposable
{
void Commit();
Database Database { get; }
}
public interface IUnitOfWorkProvider
{
IUnitOfWork GetUnitOfWork(string connectionString);
}
public class PetaPocoUnitOfWorkProvider : IUnitOfWorkProvider
{
public IUnitOfWork GetUnitOfWork(string connectionString)
{
return new PetaPocoUnitOfWork(connectionString);
}
}
public interface IRepository<T>
{
void Insert(IUnitOfWork unitOfWork, T entity);
void Update(IUnitOfWork unitOfWork, T entity);
void Delete(IUnitOfWork unitOfWork, T entity);
T Fetch(IUnitOfWork unitOfWork, long uid);
}
public class PetaPocoUnitOfWork : IUnitOfWork
{
private readonly Transaction _petaTransaction;
private readonly Database _database;
public PetaPocoUnitOfWork(string connectionString)
{
_database = new Database(connectionString);
_petaTransaction = new Transaction(_database);
}
public void Dispose()
{
_petaTransaction.Dispose();
}
public Database Database
{
get { return _database; }
}
public void Commit()
{
_petaTransaction.Complete();
}
}
public class FakeRepository : IRepository<Fake>
{
public void Insert(IUnitOfWork unitOfWork, Fake entity)
{
unitOfWork.Database.Save(entity);
}
public void Update(IUnitOfWork unitOfWork, Fake entity)
{
unitOfWork.Database.Update(entity);
}
public void Delete(IUnitOfWork unitOfWork, Fake entity)
{
unitOfWork.Database.Delete(entity);
}
public FakeJobFact Fetch(IUnitOfWork unitOfWork, long uid)
{
return unitOfWork.Database.Fetch<Fake>("SELECT * FROM Fakes WHERE [FakeId] = #0", uid).FirstOrDefault();
}
}
PS:
I have adapted the code according to #Plebsori current answer:
public abstract class BaseRepository<T>
{
protected IDatabase Database
{
get
{
return UnitOfWork.Current;
}
}
public void Insert(T entity)
{
Database.Save(entity);
}
public void Update(T entity)
{
Database.Update(entity);
}
public void Delete(T entity)
{
Database.Delete(entity);
}
}
public interface IRepository<T>
{
void Insert(T entity);
void Update(T entity);
void Delete(T entity);
T Fetch(long uid);
}
public interface IUnitOfWork : IDisposable
{
void Commit();
Database Database { get; }
}
public interface IUnitOfWorkProvider
{
IUnitOfWork GetUnitOfWork(string connectionString);
}
public class PetaPocoUnitOfWork : IUnitOfWork
{
private readonly Transaction _petaTransaction;
private readonly Database _database;
public PetaPocoUnitOfWork(string connectionString)
{
_database = new Database(connectionString);
_petaTransaction = new Transaction(_database);
}
public void Dispose()
{
UnitOfWork.Current = null;
_petaTransaction.Dispose();
}
public Database Database
{
get { return _database; }
}
public void Commit()
{
_petaTransaction.Complete();
}
}
public class PetaPocoUnitOfWorkProvider : IUnitOfWorkProvider
{
public IUnitOfWork GetUnitOfWork(string connectionString)
{
if (UnitOfWork.Current != null)
{
throw new InvalidOperationException("Existing unit of work.");
}
var petaPocoUnitOfWork = new PetaPocoUnitOfWork(connectionString);
UnitOfWork.Current = petaPocoUnitOfWork.Database;
return petaPocoUnitOfWork;
}
}
public static class UnitOfWork
{
[ThreadStatic] public static IDatabase Current;
}
You may or may not like, but here's how I removed the passing of unit of work and the unit of work from the interface.
var unitOfWorkProvider = new PetaPocoUnitOfWorkProvider();
var repository = new FakeRepository();
var fake = new Fake
{
// etc.
};
using (var uow = unitOfWorkProvider.GetUnitOfWork("BlaConnectionString"))
{
repository.Insert(fake);
uow.Commit();
}
Code
public interface IUnitOfWorkProvider
{
IUnitOfWork GetUnitOfWork(string connectionString);
}
public static class UnitOfWork
{
[ThreadStatic]
public static IUnitOfWork Current { get; set; }
}
public class PetaPocoUnitOfWorkProvider : IUnitOfWorkProvider
{
public IUnitOfWork GetUnitOfWork(string connectionString)
{
if (UnitOfWork.Current != null)
{
throw new InvalidOperationException("Existing unit of work.");
}
UnitOfWork.Current = new PetaPocoUnitOfWork(connectionString);
return UnitOfWork.Current;
}
}
public interface IRepository<T>
{
void Insert(T entity);
void Update(T entity);
void Delete(T entity);
T Fetch(long uid);
}
public class PetaPocoUnitOfWork : IUnitOfWork
{
private readonly Transaction _petaTransaction;
private readonly Database _database;
public PetaPocoUnitOfWork(string connectionString)
{
_database = new Database(connectionString);
_petaTransaction = new Transaction(_database);
}
public void Dispose()
{
UnitOfWork.Current = null;
_petaTransaction.Dispose();
}
public Database Database
{
get { return _database; }
}
public void Commit()
{
_petaTransaction.Complete();
}
}
public abstract class BaseRepository<T> : IRepository<T>
{
protected IDatabase Db
{
get
{
return UnitOfWork.Current;
}
}
}
public class FakeRepository : BaseRepository<T>
{
public void Insert(Fake entity)
{
Db.Save(entity);
}
public void Update(Fake entity)
{
Db.Update(entity);
}
public void Delete(Fake entity)
{
Db.Delete(entity);
}
public FakeJobFact Fetch(long uid)
{
return Db.Fetch<Fake>("SELECT * FROM Fakes WHERE [FakeId] = #0", uid).FirstOrDefault();
}
}
I have general class.
I need create method get seingleOrDefault by ID?
How to do this?
public T GetByID(int id)
{
_entities.Set<T>().Single(x => x.);
}
general class:
public abstract class GenericRepository<C, T> : IGenericRepository<T>
where T : class
where C : DbContext, new()
{
private C _entities = new C();
public C Context
{
get { return _entities; }
set { _entities = value; }
}
public virtual IQueryable<T> GetAll()
{
IQueryable<T> query = _entities.Set<T>();
return query;
}
public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
IQueryable<T> query = _entities.Set<T>().Where(predicate);
return query;
}
public virtual void Add(T entity)
{
_entities.Set<T>().Add(entity);
}
public virtual void Delete(T entity)
{
_entities.Set<T>().Remove(entity);
}
public virtual void Edit(T entity)
{
_entities.Entry(entity).State = System.Data.EntityState.Modified;
}
public virtual void Save()
{
_entities.SaveChanges();
}
}
If you are using DbContext then method Set<T>() returns DbSet<T> instead of ObjectSet<T>. DbSet<T> has method DbSet<T>.Find(params object[] keyValues) which does exactly what you are trying to implement:
This method uses the primary key value to attempt to find an entity tracked by the
context. If the entity is not in the context then a query will be
executed and evaluated against the data in the data source, and null
is returned if the entity is not found in the context or in the data
source.
Usage:
public T GetByID(int id)
{
return _entities.Set<T>().Find(id);
}
If you want to do this in a generic fashion, you need to add a generic constraint on T.
Something like
public interface IEntity
{
int Id { get; set; }
}
public abstract class GenericRepository<C, T> : IGenericRepository<T>
where T : class, IEntity
where C : DbContext, new()
{
public T GetByID(int id)
{
_entities.Set<T>().SingleOrDefault(x => x.Id == id);
}
...
}