I'm having a problem in using update in my generic repository. here is the error
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded.
here is my code, everything else works except the update.
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using GameCommerce.Core.Interfaces;
namespace GameCommerce.Infrastructure
{
public class Repository<T> : IRepository<T> where T : class
{
private AppDbContext _context = new AppDbContext();
private IDbSet<T> _entities;
public T Get(int id)
{
return Entities.Find(id);
}
public IEnumerable<T> GetAll()
{
return Entities.ToList();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return Entities.Where(predicate);
}
public T SingleOrDefault(Expression<Func<T, bool>> predicate)
{
return Entities.SingleOrDefault(predicate);
}
public void Add(T entity)
{
Entities.Add(entity);
_context.SaveChanges();
}
public void AddRange(IEnumerable<T> entities)
{
foreach(var entity in entities)
Entities.Add(entity);
_context.SaveChanges();
}
public void Update(T entity)
{
_context.Entry(entity).State = EntityState.Modified;
_context.SaveChanges();
}
public void Remove(T entity)
{
Entities.Remove(entity);
_context.SaveChanges();
}
public void RemoveRange(IEnumerable<T> entities)
{
foreach(var entity in entities)
Entities.Remove(entity);
_context.SaveChanges();
}
protected IDbSet<T> Entities
{
get
{
if(_entities == null)
{
_entities = _context.Set<T>();
}
return _entities;
}
}
}
}
Related
I have the following statement which get all the list item and then do loop to delete each item from the database.
Is there a better way to handle deleting all items?
IRepository.cs
public interface IRepository<T> where T : new()
{
TableQuery<T> AsQueryable();
T GetById(object id);
List<T> GetWithChildren(Expression<Func<T, bool>> predicate = null);
void Delete(T entity);
void CreateTable();
void Clear();
}
AnotherService.cs
protected IRepository<TModel> Repository => _repository ?? (_repository = new Repository<TModel>(_factory));
Service.cs
private IRepository<Class> _classRepo;
public void DeleteClasses(string classId)
{
foreach (var class in _classRepo.Get(x => x.ClassId.Equals(classId)).ToList())
{
_classRepo.Delete(class);
}
}
I am creating a new MVC solution using the instruction of an udemy video. The instructor uses the repository pattern to interact with the models but he uses an int. I am, on the other hand, using a Guid, which he does not show. I know that while an int is created automatically, I need to explicitly create the Guid as I do here:
[HttpPost]
public ActionResult CreateCarrier(Carrier carrier)
{
carrier.CarrierID = System.Guid.NewGuid();
carriers.Insert(carrier);
carriers.Commit();
return RedirectToAction("CarrierList");
}
However, since I have numerous classes I think this would be a lot of extra code. Shouldn't I create the Guid for the entity id right before I insert it? I just cannot figure out how to do it in the repository. Here is the repository code:
public abstract class RepositoryBase<TEntity> : IRepositoryBase<TEntity> where TEntity : class
{
internal DataContext context;
internal DbSet<TEntity> dbSet;
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
}
and here is the interface:
namespace WarehouseScheduling.DAL.Contracts
{
public interface IRepositoryBase<TEntity> where TEntity : class
{
void Commit();
void Delete(TEntity entity);
void Delete(object id);
void Dispose();
IQueryable<TEntity> GetAll();
IQueryable<TEntity> GetAll(object filter);
TEntity GetById(object id);
TEntity GetFullObject(object id);
IQueryable<TEntity> GetPaged(int top = 20, int skip = 0, object orderBy = null, object filter = null);
void Insert(TEntity entity);
void Update(TEntity entity);
}
}
YOu can enforce the generic type TEntity to be an interface that allow getting and setting Guid
public interface IHasGuid
{
Guid Id { get; set; }
}
Then you can put restriction on your repository class/interface so that it only works with entities of type IHasGuid
namespace WarehouseScheduling.DAL.Contracts
{
public interface IRepositoryBase<TEntity> where TEntity : IHasGuid
{
void Commit();
void Delete(TEntity entity);
void Delete(object id);
void Dispose();
IQueryable<TEntity> GetAll();
IQueryable<TEntity> GetAll(object filter);
TEntity GetById(object id);
TEntity GetFullObject(object id);
IQueryable<TEntity> GetPaged(int top = 20, int skip = 0, object orderBy = null, object filter = null);
void Insert(TEntity entity);
void Update(TEntity entity);
}
}
and also modify the implementation similarly but add code to automatically add in the Guid
public abstract class RepositoryBase<TEntity> : IRepositoryBase<TEntity> where TEntity : IHasGuid
{
internal DataContext context;
internal DbSet<TEntity> dbSet;
public virtual void Insert(TEntity entity)
{
entity.Id = new Guid();
dbSet.Add(entity);
}
}
Remember that your entity (Carrier in this case) has to implement IHasGuid
public class Carrier : IHasGuid
{
public Guid Id { get; set; }
// other fields below
}
I have taken over a project from a collegue, who uses the IRepository pattern. I have never used it before, so I have some problems understanding how to make a WHERE clause or an ANY clause.
Previously I had the following code, which uses the DataContext repository (the actual implementation, where I can use where clauses:
IQueryable<Office> officeList = repository.Offices;
if (specification.CountryId > 0)
{
officeList = repository.Offices.Where(c => c.CountryId == specification.CountryId);
}
if (specification.LetterSize != null)
{
officeList =
officeList.Where(
c => c.OfficeProducts.Any(d => d.OfficeProductDetail.Size == (int)specification.LetterSize));
}
return officeList.ToList();
I would like to understand how to get a code snippet like the one above to work using the IRepository pattern. I have tried to make an implementation of a WHERE/QUERY, but could not get it to work.
My question:
How do you implement a WHERE/ANY statement in practice, so I can do something like the code snippet above?
My IRepository:
public interface IRepository
{
T GetById<T>(long id) where T : class;
void Create<T>(T entity) where T : class;
void Update<T>(T entity) where T : class;
void SaveOrUpdate<T>(T entity) where T : class;
void Delete<T>(T entity) where T : class;
IList<T> FindAll<T>(params OrderBy[] orders) where T : class;
int Count<T>(Expression<Func<T, bool>> whereExpression) where T : class;
bool Exists<T>(Expression<Func<T, bool>> whereExpression) where T : class;
T FindFirst<T>(Expression<Func<T, bool>> whereExpression, params OrderBy[] orders) where T : class;
PaginatedResult<T> Find<T>(Expression<Func<T, bool>> whereExpression, int pageIndex, int pageSize, params OrderBy[] orders) where T : class;
void ExecuteNativeSQL(string sql);
}
The implementation:
public class EFRepository : IRepository
{
private IDBFactory databaseFactory;
private LetterAmazerContext dataContext;
public EFRepository(IDBFactory databaseFactory)
{
this.databaseFactory = databaseFactory;
}
protected LetterAmazerContext DataContext
{
get { return dataContext ?? (dataContext = databaseFactory.Get()); }
}
public T GetById<T>(long id) where T : class
{
IDbSet<T> dbset = DataContext.Set<T>();
return dbset.Find(id);
}
public void Create<T>(T entity) where T : class
{
IDbSet<T> dbset = DataContext.Set<T>();
dbset.Add(entity);
}
public void Update<T>(T entity) where T : class
{
dataContext.Entry(entity).State = EntityState.Modified;
}
public void SaveOrUpdate<T>(T entity) where T : class
{
throw new NotImplementedException();
}
public void Delete<T>(T entity) where T : class
{
IDbSet<T> dbset = DataContext.Set<T>();
dbset.Remove(entity);
}
public IList<T> FindAll<T>(params OrderBy[] orders) where T : class
{
IDbSet<T> dbset = DataContext.Set<T>();
var query = dbset.Where(t => true);
query = ApplyOrders<T>(query, orders);
return query.ToList<T>();
}
public int Count<T>(Expression<Func<T, bool>> whereExpression) where T : class
{
IDbSet<T> dbset = DataContext.Set<T>();
return dbset.Count<T>(whereExpression);
}
public bool Exists<T>(Expression<Func<T, bool>> whereExpression) where T : class
{
IDbSet<T> dbset = DataContext.Set<T>();
return dbset.Count<T>(whereExpression) != 0;
}
public T FindFirst<T>(Expression<Func<T, bool>> whereExpression, params OrderBy[] orders) where T : class
{
IDbSet<T> dbset = DataContext.Set<T>();
var query = dbset.Where(whereExpression);
query = ApplyOrders<T>(query, orders);
return query.SingleOrDefault<T>();
}
public PaginatedResult<T> Find<T>(Expression<Func<T, bool>> whereExpression, int pageIndex, int pageSize, params OrderBy[] orders) where T : class
{
IDbSet<T> dbset = DataContext.Set<T>();
PaginatedResult<T> results = new PaginatedResult<T>();
var query = dbset.AsExpandable().Where(whereExpression);
query = ApplyOrders<T>(query, orders);
results.Results = query.Skip<T>(pageIndex * pageSize).Take<T>(pageSize).ToList<T>();
results.TotalItems = dbset.AsExpandable().LongCount(whereExpression);
return results;
}
public void ExecuteNativeSQL(string sql)
{
DataContext.Database.ExecuteSqlCommand(sql);
}
private IQueryable<T> ApplyOrders<T>(IQueryable<T> query, params OrderBy[] orders)
{
if (orders == null || orders.Length == 0) return query;
foreach (var order in orders)
{
query = query.OrderBy(order.ToString());
}
return query;
}
}
Your repository is at the moment open for arbitrary expressions, including potentially expressions that cannot be evaluated by the implementation.
On one hand this is a potential risk of not being able to deliver an implementation that matches so open contract.
On the other hand, why don't you just then expose it a bit more:
public interface IRepository
{
...
IQueryable<T> Query<T>();
}
and
public class EFRepository : IRepository
{
...
public IQueryable<T> Query<T>()
{
return DataContrxt.Set<T>();
}
}
Note that if you decide to go that way, most of your specific query methods doesn't make sense anymore as such open generic queryable interface satisfies most needs.
Note also that the same concern applies there, if you have multiple implementations you can't possibly guarantee that the contract is satisfied in the same way. Also, your potential client can easily create a query the provider will reject. If you accept these issues, the proposed solution solves your issue as you can now query the repository for almost anything.
And the last note, if you don't plan to have multiple implementations, remove the repository layer completely. The EF context is a unit of work with repositories inside. Starting from version 6, the context can be mocked so unit testing is possible.
today I wanted to start unit-testing a little asp.net MVC 3 Web (test) application to learn some new stuff.
But things went worse then I had expected ...
I've now read some threads about unit testing in relation with Entity framework and now I first want to implement interfaces for my entity framework related classes so that I can implement an in memory "database" for my unit tests.
My code base is from ASP.NET MVC tutorial. I've read MSDN but it doesn't help me in my cases.
I'd like to show you my code. I'm using a unit of work pattern with repositories:
Unit of work:
public class SqlUnitOfWork : IUnitOfWork, IDisposable
{
private SqlContext context = new SqlContext();
private IGenericRepository<Message> messageRepository;
private IGenericRepository<Receipt> receiptRepository;
private IGenericRepository<Useraccount> useraccountRepository;
private bool disposed = false;
public IGenericRepository<Message> MessageRepository
{
get
{
if (this.messageRepository == null)
{
this.messageRepository = new SqlGenericRepository<Message>(context);
}
return messageRepository;
}
}
public IGenericRepository<Receipt> ReceiptRepository
{
get
{
if (this.receiptRepository == null)
{
this.receiptRepository = new SqlGenericRepository<Receipt>(context);
}
return receiptRepository;
}
}
public IGenericRepository<Useraccount> UseraccountRepository
{
get
{
if (this.useraccountRepository == null)
{
this.useraccountRepository = new SqlGenericRepository<Useraccount>(context);
}
return useraccountRepository;
}
}
public SqlUnitOfWork()
{
}
~SqlUnitOfWork()
{
}
public 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 Save()
{
context.SaveChanges();
}
}
This one implements an interface I've created.
My generic repository for sql:
public class SqlGenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
internal SqlContext context;
internal DbSet<TEntity> dbSet;
public SqlGenericRepository(SqlContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
~SqlGenericRepository()
{
}
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
It implements an interface I've programmed:
public interface IGenericRepository<TEntity> where TEntity : class
{
IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
TEntity GetByID(object id);
void Insert(TEntity entity);
void Delete(object id);
void Delete(TEntity entityToDelete);
void Update(TEntity entityToUpdate);
}
I would now like to implement an "InMemoryGenericRepository" for my unit tests, then an "InMemoryUnitOfWork".
How would those "InMemoryGenericRepository" look like?
I think I would use a generic List inside this repository where all data is stored:
IEnumerable<TEntity> List { get; set; }
But how can I adapt this method:
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
so it's working with my
IEnumerable<TEntity> List { get; set; }
I hope you made it until the end of my question.
If your classes are POCO then they're looking like this:
namespace Project.Model // auto-generated Foo.cs
{
public partial class Foo // notice partiality
{
}
}
Then you write this:
namespace Project.Model // custom Foo.cs in another folder
{
public partial class Foo : IEntity // notice interface
{
}
}
The generic repository pattern is not a good pattern. It gets you a lot of pain in exchange for storage independence (which you likely don't need. You like to have it but you don't really need it). You will really have a hard time to write a queryable in-memory repository for a few reasons:
the entities have relationships which must be setup correctly
in-memory queries behave differently than SQL queries (for example, they are case-sensitive)
in-memory queries have no optimizer which can lead to excessive runtime of tests
you now have to test the tests, basically, so you can be sure that no difference in behavior exists
Also, by abstracting away your ORM you can use none of its features. You can only use the most generic and general features.
I have done exactly this a few years ago and the pain just doesn't end. I found it to be a good pattern to use a real SQL database for tests. That way you don't need any repository and can test the real thing. This has its problems but it is workable.
The solution to this question is to abandon the generic repository pattern.
Also you could rewrite your lazy properties with:
private IGenericRepository<Message> messageRepository;
public IGenericRepository<Message> MessageRepository
{
get
{
return messageRepository ?? (messageRepository = new IGenericRepository<Message>());
}
}
or
private Lazy<IGenericRepository<Message>> messageRepository = new Lazy<IGenericRepository<Message>>(new IGenericRepository<Message>()));
public IGenericRepository<Message> MessageRepository
{
get
{
return messageRepository.Value;
}
}
i using below repository pattern. when i instance from the class getting this exception:
public interface IRepository<TEntity> : IDisposable where TEntity : class
{
IQueryable<TEntity> GetQuery();
IEnumerable<TEntity> GetAll();
IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);
TEntity Single(Expression<Func<TEntity, bool>> predicate);
TEntity First(Expression<Func<TEntity, bool>> predicate);
void Add(TEntity entity);
void Delete(TEntity entity);
void Attach(TEntity entity);
void SaveChanges();
void SaveChanges(SaveOptions options);
}
public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
private ObjectContext _context;
private IObjectSet<TEntity> _objectSet;
public GenericRepository(ObjectContext context)
{
_context = context;
_objectSet = _context.CreateObjectSet<TEntity>();
}
public IQueryable<TEntity> GetQuery()
{
return _objectSet;
}
public IEnumerable<TEntity> GetAll()
{
return GetQuery().AsEnumerable();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _objectSet.Where<TEntity>(predicate);
}
public TEntity Single(Expression<Func<TEntity, bool>> predicate)
{
return _objectSet.Single<TEntity>(predicate);
}
public TEntity First(Expression<Func<TEntity, bool>> predicate)
{
return _objectSet.First<TEntity>(predicate);
}
public void Delete(TEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_objectSet.DeleteObject(entity);
}
public void Add(TEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_objectSet.AddObject(entity);
}
public void Attach(TEntity entity)
{
_objectSet.Attach(entity);
}
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 && _context != null)
{
_context.Dispose();
_context = null;
}
}
}
using:
var db = new AdventureWorks2012Entities();
IRepository<Person> person = new GenericRepository<Person>();
exception:
Problem is that you are using Entity Framework 4.1 or later, which has DbContext wrapper around ObjectContext. But your repository still usess ObjectContext. Add another constructor, which accepts DbContext:
public GenericRepository(DbContext context)
{
_context = (context as IObjectContextAdapter).ObjectContext;
_objectSet = _context.CreateObjectSet<TEntity>();
}
You can retrieve wrapped ObjectContext instance by casting DbContext to IObjectContextAdapter interface. Another option is updating your repository class to use latest DbContext, but that will require a little bit more coding, than simply adding one constructor:
public class GenericRepository<TEntity> : IRepository<TEntity>
where TEntity : class
{
private DbContext _context; // instead of ObjectContext
private DbSet<TEntity> _set; // instead of IObjectSet<TEntity>
public GenericRepository(DbContext context)
{
_context = context;
_set = _context.Set<TEntity>();
}
public IQueryable<TEntity> GetQuery()
{
return _set;
}
public IEnumerable<TEntity> GetAll()
{
return GetQuery().AsEnumerable();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _set.Where<TEntity>(predicate);
}
// etc
}
This is all in the error message, the first one is simple enough - your repository expects an ObjectContext parameter (which you don't provide).
The second one is basically saying that your db instance is not of type ObjectContext or at least can't be downcast to that particular type. If your sure AdventureWorks2012Entities derives from ObjectContext then you could do a direct cast e.g.
IRepository<Person> repo = new GenericRepository<Person>((ObjectContext)db);
You can pass a DbSet to your repository, so:
var db = new AdventureWorks2012Entities();
IRepository<Person> person = new GenericRepository<Person>(db.Person);
Where db.Person is declared in the AdventureWorks2012Entities DbContext class.
I'm developing a UnitOfWork/Repository abstraction layer to easily switch from NHibernate/EntityFramework/Raven and others and to better allow the tests.
Here the source code and here the Nuget package. I've to change the code base to better support DDD methodology, in particular:
remove the unit of work class, not needed because work with one aggregate per time
add the Commit method to the repository