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.
Related
Im trying to create a generic repository ,here is my IGenericRepository:
public interface IGenericRepository<TEntity> where TEntity : class
{
Task<IEnumerable<TEntity>> FindByFilterAsync(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] including);
Task<TEntity> GetByIdAsync(int id);
Task<bool> InsertAsync(TEntity obj);
}
here is the implementation of the respository:
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
private readonly IServiceScopeFactory scopeFactory;
public GenericRepository(IServiceScopeFactory scopeFactory) => this.scopeFactory = scopeFactory;
public async Task<IEnumerable<TEntity>> FindByFilterAsync(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] including)
{
using (var scope = this.scopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<CleanArchitectureContext>();
var x = db.Set<TEntity>().AsQueryable();
if (including != null)
{
including.ToList().ForEach(s =>
{
if (s != null)
{
x = x.Include(s);
}
});
}
return await x.Where(predicate).ToListAsync().ConfigureAwait(true);
}
}
public Task<TEntity> GetByIdAsync(int id)
{
throw new NotImplementedException();
}
public Task<bool> InsertAsync(TEntity obj)
{
throw new NotImplementedException();
}
}
now lets say i need to have an interface which is going to inherit from the IGeneric repository and store data in the db:
public interface IStorePayoutRepository:IGenericRepository<PayoutModel>
{
}
so far so good, the problem is if i want to have a class and inherit from IStorePayoutRepository,then i need to implement all the members inside that which is not what i want,because i need only the store one(save or insert into db),
public class PayoutRepository : IGenericRepository<PayoutEntity>
{
//Im forced to implement all the members inside generic interface
}
as you see its not very optimal to implement all the members everytime as they could be irrelevant to the usecase,whats the right way here?i appreciate your help
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>
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);
}
}
}
I want to save a record using the entity framework with windows forms. On database I have many tables which are similar to each other; they all have on auto-increment ID column and a string column. What I want is to create a set of buttons that when one of them is pressed it fills a listbox with the designated table. Also another fixed button will insert the string in the fixed textbox into the table selected by the button pressed previously.
The problem is I can't use the created context item in the second button.
Here is the code for one the buttons on the left:
private void btnBB_Click(object sender, EventArgs e)
{
lbItems.DataSource = GsmContext.bbler;
lbItems.DisplayMember = "bb";
bb = new bbler();
bb.bb = txtItem.Text;
GsmContext.AddTobbler(bb);
}
And here is the code for saving the item in the textbox:
private void SaveItem(object sender, EventArgs e)
{
if (txtItem.Text == string.Empty)
{ this.errorProvider1.SetError(txtItem, "Değer girin"); }
else
{
try
{
GsmContext.SaveChanges();
txtItem.Clear();
}
catch (SqlException x)
{
MessageBox.Show(x.Message);
}
}
}
This is what I have got. My Entity framework model defines all the classes from the database. And then I create an interface IRepository and a DataRepository class.
public interface IRepository<T> : IDisposable where T : class
{
IQueryable<T> Fetch();
IEnumerable<T> GetAll();
IEnumerable<T> Find(Func<T, bool> predicate);
T Single(Func<T, bool> predicate);
T First(Func<T, bool> predicate);
void Add(T entity);
void Delete(T entity);
void Attach(T entity);
void Detach(T entity);
void UpdateChanges(T entity);
void SaveChanges();
void SaveChanges(SaveOptions options);
}
public class DataRepository<T> : IRepository<T> where T : class
{
private ObjectContext _context;
private IObjectSet<T> _objectSet;
public DataRepository()
: this(new ModelContainer()) //ModelContainer is the name of the EF model class.
{
}
public DataRepository(ObjectContext context)
{
_context = context;
_objectSet = _context.CreateObjectSet<T>();
}
public IQueryable<T> Fetch()
{
return _objectSet;
}
public IEnumerable<T> GetAll()
{
return Fetch().AsEnumerable();
}
public IEnumerable<T> Find(Func<T, bool> predicate)
{
return _objectSet.Where<T>(predicate);
}
public T Single(Func<T, bool> predicate)
{
return _objectSet.Single<T>(predicate);
}
public T First(Func<T, bool> predicate)
{
return _objectSet.First<T>(predicate);
}
public void Delete(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_objectSet.DeleteObject(entity);
}
public void Delete(Func<T, bool> predicate)
{
IEnumerable<T> records = from x in _objectSet.Where<T>(predicate) select x;
foreach (T record in records)
{
_objectSet.DeleteObject(record);
}
}
public void Add(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_objectSet.AddObject(entity);
}
public void Attach(T entity)
{
_objectSet.Attach(entity);
}
public void Detach(T entity)
{
_objectSet.Detach(entity);
}
public void UpdateChanges(T entity)
{
Add(entity);
_context.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);
SaveChanges();
}
public void SaveChanges()
{
_context.SaveChanges();
}
public void SaveChanges(SaveOptions options)
{
_context.SaveChanges(options);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
}
}
Then select records like this:
public IList<MyDbClass> GetMyDbClassData()
{
IList<MyDbClass> myDbClassData = null;
using (IRepository<MyDbClass> repository = new DataRepository<MyDbClass>())
{
myDbClassData = (from x in repository.GetAll()
select x).ToList();
}
return myDbClassData;
}
To create a new record:
public void CreateUser(User user)
{
using (IRepository<User> repository = new DataRepository<User>())
{
repository.Add(user);
repository.SaveChanges();
}
}