I want to build generic repository to make it easy in implementing..now I want to make interface to used it in dependency injection in my domain service but I can't
I want to build generic repository to make it easy in implementing.I created generic abstract repository that get entity and its context.now I want to make interface to used it in dependency injection in my domain service
my generic repository:
public abstract class Repository<T,K>:IRepository<T,K>
{
private Type t;
private K _Context;
private bool disposed = false;
public Repository(K Context)
{
_Context = Context;
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
_Context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Delete(object id)
{
T t = _Context.Set<T>().Find(id);
_Context.Set<T>().Remove(t);
}
public T Get(object id)
{
return _Context.Set<T>().Find(id);
}
public IEnumerable<T> getList()
{
return _Context.Set<T>().ToList();
}
public void insert(T t)
{
_Context.Set<T>().Add(t);
}
public void Save()
{
_Context.SaveChanges();
}
public void Update(T t)
{
_Context.Entry(t).State = EntityState.Modified;
}
}
}
my repository interface:
public interface IRepository<T,K> where T : BaseEntity where K : BaseContext<K>
{
T Get(object id);
IEnumerable<T> getList();
void insert(T t);
void Delete(object id);
void Update(T t);
void Save();
}
my error is "the Type 'T' can not be used as type parameter 'T' in the generic type....The type 'T' cannot be used as type parameter 'T' in the generic type or method 'IRepository'. There is no boxing conversion or type parameter conversion from 'T' to 'DomainModel.BaseEntity" and I want to know how can I resolve this problem
You must put the where constraints on the class Repository<T,K> as well i.e.:
public abstract class Repository<T,K>:IRepository<T,K> where T : BaseEntity where K : BaseContext<K>
This is because C# knows nothing about the T in Repository<T,K>, but it needs to satisfy the where criteria in IRepository<T,K>
Related
I'm using repository layer. My problem here is GetAll() method is too slow when join a table with large records. It is taking 40 seconds to run a simple query.
IGenericRepository:
public interface IGenericRepository<TEntity>
{
TEntity FindBy(Expression<Func<TEntity, bool>> predicate);
IEnumerable<TEntity> GetAll();
TEntity GetById(int id);
TEntity Insert(TEntity entity);
TEntity Update(TEntity entity);
void Delete(object id);
void Save();
}
GenericRepository:
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
private MyStoreContext _dbContext;
protected DbSet<TEntity> DbSet;
public GenericRepository()
{
_dbContext = new MyStoreContext ();
DbSet = _dbContext.Set<TEntity>();
}
public TEntity FindBy(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate).SingleOrDefault();
}
public IEnumerable<TEntity> GetAll()
{
return DbSet.AsNoTracking();
}
public TEntity GetById(int id)
{
return DbSet.Find(id);
}
public TEntity Insert(TEntity entity)
{
DbSet.Add(entity);
Save();
return entity;
}
public TEntity Update(TEntity obj)
{
DbSet.Attach(obj);
_dbContext.Entry(obj).State = EntityState.Modified;
Save();
return obj;
}
public void Delete(object id)
{
TEntity entityToDelete = DbSet.Find(id);
Delete(entityToDelete);
}
public void Delete(TEntity entityToDelete)
{
if (_dbContext.Entry(entityToDelete).State == EntityState.Detached)
{
DbSet.Attach(entityToDelete);
}
DbSet.Remove(entityToDelete);
Save();
}
public void Save()
{
try
{
_dbContext.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
System.Console.WriteLine("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage); // you just put the log to know the errors
}
}
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_dbContext != null)
{
_dbContext.Dispose();
_dbContext = null;
}
}
}
}
Linq:
var conceptosDetalle = from pf in _parFactfRepository.GetAll()
join inve in _inveRepository.GetAll() on pf.CVE_ART equals inve.CVE_ART
where inve.STATUS == "A" && pf.CVE_DOC == cveDoc
orderby inve.CTRL_ALM, inve.CVE_ART
select new MyViewModel()
{
CTRL = inve.CTRL_ALM,
CVE_ART = inve.CVE_ART,
UNID = "PIEZA",
CANT = pf.CANT,
DESCR = inve.DESCR,
PREC = pf.PREC,
DESC1 = pf.DESC1,
TOTIMP4 = pf.TOTIMP4
};
The query returns 10 records. parFactfRepository contains 992590 rows, inveRepository contains 41908 rows.
What i'm doing wrong?
That's because you're mixing and matching repository-based queries and LINQ queries. Rather than doing a true join, you're fetching all the rows for each table and then joining them in-memory.
The easiest way to fix this is probably to just return IQueryable<TEntity> rather than IEnumerable<TEntity> from your GetAll method. Using IEnumerable<TEntity> forces the query to evaluate. If you're going to return IEnumerable<TEntity> your data should be fully-baked, i.e. no further alterations to the query are necessary (including joins).
That said, this is yet one more failing of trying to use the repository pattern with EF. If you aren't very careful, you end up introducing logical errors like this that aren't obvious as to why they are happening. Entity Framework already implements the repository pattern; that is what a DbSet is. If you want an abstraction over that, introduce a service layer. With that, you'd simply have a method like:
public IEnumerable<MyViewModel> GetConceptosDetalle()
{
...
}
And that method would contain this entire query (using EF directly, rather than your completely unnecessary repository layer). That way, your application simply calls a method that returns the data it needs, and that service layer contains all the logic. That's true abstraction. With a repository, you're bleeding logic all over your codebase.
Note: I made it return MyViewModel simply for ease of explanation, but in reality, you should return some sort of DTO, which you could then map to your view model. It would be bad idea to leak view business logic into a service layer.
I have the interface.
public interface IRepository<T> where T : class
{
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(Expression<Func<T, bool>> filter);
Then
public interface ICatRepository : IRepository<Cat>
{
}
Also I have the base class.
public abstract class RepositoryBase<T> where T : class
{
private DbContext dataContext;
protected readonly IDbSet<T> dbset;
protected RepositoryBase(IDatabaseFactory databaseFactory)
{
DatabaseFactory = databaseFactory;
dbset = DataContext.Set<T>();
}
protected IDatabaseFactory DatabaseFactory
{
get; private set;
}
protected DbContext DataContext
{
get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
dbset.Add(entity);
}
public virtual void Update(T entity)
{
dbset.Attach(entity);
dataContext.Entry(entity).State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
dbset.Remove(entity);
}
public virtual void Delete(Expression<Func<T, bool>> filter)
{
IEnumerable<T> objects = dbset.Where<T>(filter).AsEnumerable();
foreach (T obj in objects)
dbset.Remove(obj);
}
Now I have the implementation class.
class CatRepository : RepositoryBase<Cat>, ICatRepository
{
public CatRepository(IDatabaseFactory databaseFactory) : base(databaseFactory)
{
}
public void Add(Cat entity)
{
throw new NotImplementedException();
}
public void Delete(Cat entity)
{
throw new NotImplementedException();
}
public void Delete(Expression<Func<Cat, bool>> filter)
{
throw new NotImplementedException();
}
My entity framework knowledge is little rusty. Not sure how to implement Add, Delete methods etc. Please give me a hint. Code snippet is warmly welcomed. Thanks.
Not sure how to implement Add, Delete methods
They are already implemented in RepositoryBase.
Your CatRepository inherits from your generic RepositoryBase which has its generic parameter set to your Cat domain entities. Your Add and Delete is already implemented in your RepositoryBase class.
The purpose of generic repository is to have common logic grouped together, like Add(), Delete(), AddRange(), DeleteRange(), and the purpose of your CatRepository is to have extremely specific implementation like GetNaughtiestCat() method. If you don't have these implementations, you could still use the GenericRepository with the generic parameter set to Cat, you need to remove the abstract keyword.
I am trying to write an exception handler class that converts from types of EF exceptions to HttpStatusCodes.
I know how to handle the catching and sending the message to the ApiController.
public class ExceptionConverter : IExceptionConverter
{
//need the parameter
public HttpStatusCode Convert()
{
try
{
//call the void repository method here
}
catch (Exception exception)
{
if (exception is ObjectNotFoundException)
return HttpStatusCode.NotFound;
if (exception is InvalidOperationException)
return HttpStatusCode.BadRequest;
}
return HttpStatusCode.OK;
}
}
I am wondering if there is a way to write a Delagate or Generic method that could call my void repository methods.
I was thinking I could use an interface with the methods I use in my conversion
public interface IHandleCrudOperations
{
//All of these methods need to be able to take in many different parameters
//They will always need a parameter though
void Remove();
void Add();
void Edit();
void Clone();
}
As you can see I would need to be able to pass in a slew of different parameters based on the repository method in question:
//userRepository
public void Remove(int userKey)
{
//stuff
}
//groupRepository
public void Remove(string groupName)
{
//stuff
}
//someOtherRepository
public void Remove(RemoveSomethingRequest request)
{
//stuff
}
I considered using a generic methods for this:
public interface IHandleCrudOperations
{
//All of these methods need to be able to take in many different parameters
//They will always need a parameter though
void Remove<T>(T item);
void Add<T>(T item);
void Edit<T>(T item);
void Clone<T>(T item);
}
Now the implementation gets difficult:
//userRepository
public void Remove<T>(T item)
{
//SERIOUS code smell here
var userKey = (int)(object)item
_context.Users.FirstOrDefault(x => x.UserKey == userKey);
//stuff
}
//groupRepository
public void Remove<T>(T item)
{
//SERIOUS code smell here
var groupName = (string)(object)item
//stuff
}
//someOtherRepository
public void Remove<T>(T item)
{
//SERIOUS code smell here
var request = (RemoveSomethingRequest)(object)item
//stuff
}
That has many bad flaws, readability, abusing generics, generally just bad, etc....
So, since all of the methods for this operation return void:
Is this possible with Delegates?
Is there another way to handle this?
IT looks to me like you have different types of keys: Users have an int key, and Groups have a string key. So I'd make a generic interface whose methods don't have type parameters, like this:
interface IRepository<TItem, TKey>
{
void RemoveItem(TItem item);
void RemoveByKey(TKey key);
void RemoveByName(string name);
}
The implementation should be clear from that, but if it isn't leave a comment.
EDIT: You could also do this, but only if TKey and TItem are never the same, and are never string:
interface IRepository<TItem, TKey>
{
void Remove(TItem item);
void Remove(TKey key);
void Remove(string name);
}
You could move the generic parameter T to the interface itself:
public interface IHandleCrudOperations<TKey, T>
{
void Remove(TKey item);
void Add(T item);
void Edit(T item);
void Clone(T item);
}
public class UserRepository : IHandleCrudOperations<int, User>
{
public void Remove(int userKey)
{
_context.Users.FirstOrDefault(x => x.UserKey == userKey);
//stuff
}
public void Add(User user)
{
}
}
I wrote this function to save data to EF4 using POCOs classes:
public void Guardar(Pedidos myPedido)
{
using (var context = new OhmioEntities())
{
if (myPedido.ID_Pedido == 0)
{
context.Pedidos.AddObject(myPedido);
}
else
{
context.Pedidos.Attach(myPedido);
context.ObjectStateManager.ChangeObjectState(myPedido, System.Data.EntityState.Modified);
}
context.SaveChanges();
}
}
Now i want to write this in a generic way on a base class. Is there a way to decide if i need to do UPDATE or INSERT without using the ID? (ID_Pedido in this case), because the name on key field change on every object type. The rest of the code is generic. I'm traing to know if i need to use AddObject (new) or Attach(exist).
Thanks you!
look to the method InsertOrUpdate! You can make this repository more generic; For example you can create an Entity base class and use it in a generic Approach.
public class Employee
{
public int Id { get; set; }
public string FullName { get; set; }
}
Now using this we will have a simple context class
public class HRContext : DbContext
{
public DbSet<DomainClasses.Employee> Employees { get; set; }
}
After that, define the repository interface IEmployeeRepository
public interface IEmployeeRepository : IDisposable
{
IQueryable<Employee> All { get; }
IQueryable<Employee> AllIncluding(params Expression<Func<Employee, object>>[] includeProperties);
Employee Find(int id);
void InsertOrUpdate(Employee employee);
void Delete(int id);
void Save();
}
Then the Repository class called EmployeeRepository
public class EmployeeRepository : IEmployeeRepository
{
HRContext context = new HRContext();
public IQueryable<Employee> All
{
get { return context.Employees; }
}
public IQueryable<Employee> AllIncluding(params Expression<Func<Employee, object>>[] includeProperties)
{
IQueryable<Employee> query = context.Employees;
foreach (var includeProperty in includeProperties) {
query = query.Include(includeProperty);
}
return query;
}
public Employee Find(int id)
{
return context.Employees.Find(id);
}
public void InsertOrUpdate(Employee employee)
{
if (employee.Id == default(int)) {
// New entity
context.Employees.Add(employee);
} else {
// Existing entity
context.Entry(employee).State = EntityState.Modified;
}
}
public void Delete(int id)
{
var employee = context.Employees.Find(id);
context.Employees.Remove(employee);
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
I get the soruce code from :
http://blogs.msdn.com/b/wriju/archive/2013/08/23/using-repository-pattern-in-entity-framework.aspx
for example for a generic repository:
public interface IGenericRepository<T> where T : class {
IQueryable<T> GetAll();
IQueryable<T> FindBy(Expression<Func<T, bool>> predicate);
void Add(T entity);
void Delete(T entity);
void Edit(T entity);
void Save();
}
Where T is the base entity for all your entities.
here is the complete generic example:
http://www.tugberkugurlu.com/archive/generic-repository-pattern-entity-framework-asp-net-mvc-and-unit-testing-triangle
I've Found it myself! In case anyone face the same problem, here is the solution. I wrote this method:
public string getKey<T>() where T :new()
{
T _obj = new T();
return context.CreateEntityKey(_obj.ToString().Split('.')[2], _obj).EntityKeyValues[0].Key;
}
Wich return the first Primary key of the object (in my case that's enough)
And use it like this:
string sKey = getKey<GruposComerciales>();
Now i can write a generic saveorupdate method on my repository. Thank you!!!
You can query all parts of the primary key via Metadataworkspace
IDictionary<string, ICollection<EdmMember>> dict = // create instance ...
MetadataWorkspace.GetItems<EntityContainer>(DataSpace.CSpace)
.First()
.BaseEntitySets
.ToList()
.ForEach(s => dict.Add(s.ElementType.Name, s.ElementType.KeyMembers));
With this I put the defined propertys of the primary key into a dictionary for later use.
I am trying to implement an child interface using an Abstract class for most of the methods and a child of this abstract class to implement the missing methods. But the compiler keeping throwing those errors: "Foo.Bar' does not implement interface member".
After long hours staring at the code and reading tonnes of similar problems here on StackOverflow, I keep not seeing where the problem is. :S
Those are some of the "zillion" errors in my code I am having and I don't really see what is happening.
Error 2
'MyProject.Repository.EF.AccountRepository' does not implement interface member 'MyProject.Entities.IRepository<MyProject.Entities.Account,int>.FindAll()'.
'MyProject.Repository.EF.RepositoryBase<MyProject.Repository.EF.Account,int>.FindAll()' cannot implement 'MyProject.Entities.IRepository<MyProject.Entities.Account,int>.FindAll()' because it does not have the matching return type of 'System.Collections.Generic.IEnumerable<MyProject.Entities.Account>'.
D:\Projects\WebProjects\MyProject\MyProject.Repository.EF\AccountRepository.cs 5 18 MyProject.Repository.EF
//
And this is the code
//
// Repository interface
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace MyProject.Entities
{
public interface IRepository<T, EntityKey> {
void Save();
void Add(T entity);
void Remove(T entity);
T FindBy(EntityKey id);
IEnumerable<T> FindBy(Expression<Func<T, bool>> query);
IEnumerable<T> FindBy(Expression<Func<T, bool>> query, int index, int count);
IEnumerable<T> FindAll();
}
}
//
// "Child" interface
namespace MyProject.Entities
{
public interface IAccountRepository : IRepository<Account, int> {
}
}
//
// Abstract class that implement almost every method from the interface and declare two of then abstract to be implemented by a child class
using MyProject.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace MyProject.Repository.EF
{
public abstract class RepositoryBase<T, EntityKey> : IRepository<T, EntityKey> where T : class {
private IQueryable<T> objectSet;
protected MyProjectEntitiesContext Context;
public abstract string GetEntitySetName();
public abstract T FindBy(EntityKey id);
public IQueryable<T> ObjectSet
{
get { return objectSet; }
set { objectSet = value; }
}
public void Save()
{
this.Context.SaveChanges();
}
public void Add(T entity)
{
this.Context.AddObject(this.GetEntitySetName(), entity);
}
public void Remove(T entity)
{
this.Context.DeleteObject(entity);
}
public IEnumerable<T> FindAll()
{
return this.ObjectSet;
}
public IEnumerable<T> FindBy(Expression<Func<T, bool>> query)
{
return this.ObjectSet.Where(query);
}
public IEnumerable<T> FindBy(Expression<Func<T, bool>> query, int index, int count)
{
return this.FindBy(query).Skip(index).Take(count);
}
}
}
//
// Here the two missing methods are being implemented
using System.Linq;
using MyProject.Entities;
namespace MyProject.Repository.EF {
public class AccountRepository : RepositoryBase<Account, int>, IAccountRepository {
public AccountRepository()
{
this.Context = MyProjectEntitiesFactory.GetDatacontext();
this.ObjectSet = this.Context.Accounts;
}
public override string GetEntitySetName()
{
return this.Context.Accounts.EntitySet.Name;
}
public override Account FindBy(int id)
{
return this.ObjectSet.FirstOrDefault(i => i.Id == id);
}
}
}