Delete all corresponding items from SQLite - c#

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);
}
}

Related

Update in Generic Repository with Entity Framework

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;
}
}
}
}

Repository Pattern without Edit

I am reading about the Repository Pattern in C#. Every article I read with a sample repository looks like below and does not contain a definition for Edit entity.
TEntity Get(TKey id);
void Save(TEntity entity);
void Delete(TEntity entity);
Is it bad idea to have Edit method in base repository interface like below?
public interface IRepositor<T>
{
void Edit(Predicate<T> predicate, Action<T> action);
}
public class Car : IRepository<Car>
{
public void Edit(Predicate<Car> predicate, Action<Car> action)
{
var car = Context.Cars.SingleOrDefault(x => predicate(x));
if(car == null) throw new Exception("Not found");
action.Invoke(car);
}
}
public class CarController
{
public void Edit(CarViewModel vm)
{
carService.Edit(x => x.Id == vm.Id, y => y.Type == "BMW" );
}
}

Where to place multiple queries for repository

I'm not sure where to put my specific queries for business objects.
When we start using multiple table specific queries for the repository pattern, where
should these be placed? Service Layer or Repository?
For Example Please see below:
Ex:
class HR_Repository<T> : IRepository<T> where T : class
{
private readonly LoginDataContext dataContext;
public HR_Repository(LoginDataContext dataContext)
{
this.dataContext = dataContext;
}
public void Commit()
{
dataContext.SubmitChanges();
}
public IList<T> FindAll()
{
var table = this.LookupTableFor(typeof(T));
return table.Cast<T>().ToList();
}
public IQueryable<T> Find()
{
var table = this.LookupTableFor(typeof(T));
return table.Cast<T>();
}
public void Add(T item)
{
var table = this.LookupTableFor(typeof(T));
table.InsertOnSubmit(item);
}
public void Delete(T item)
{
var table = this.LookupTableFor(typeof(T));
table.DeleteOnSubmit(item);
}
private ITable LookupTableFor(Type entityType)
{
return dataContext.GetTable(entityType);
}
}
I have this class below in the repository currently. But I plan to place many more of these for other tables. This to me doesn't "feel" right.
Would multiple classes such as these be considered best practice or frowned upon?:
public static class UserQueries
{
public static Employee ByUserName(this IQueryable<Employee> employees, string username)
{
return employees.Where(u => u.User_Name == username).FirstOrDefault();
}
}
Additionally I'm planning to use another method (GetEmployeeProductivity) that essentially applies logic using data in the Employee object and data found in a separate DataRepository. So now I'm using an EmployeeRepository and a DataRepository.
Where would this go? Employee Class, Service or Repository?
Generally, your logic that makes decisions based on business rules goes in the service layer. The code that creates, updates, or deletes rows from tables (the standard CRUD functions) goes into the repository.
So if you need to retrieve data by joining multiple tables together, that's in the repository. The code that says "if this condition is met, then do this to the database" is in the service layer. If you need to add or update a row in several tables, that's still in the repository, and can either be done in one method (if the 2 tables conceptually are one, but are split into two for database efficiency reasons, like a one to many or many to many relationship), or you can use separate methods, one for each table, and just call them from one method in the service layer.
What you can also do is to encapsulate them in each class where they refer. Your second static class has the Method ByUserName who returns an Employee object. You can put this method in Employee class (The Repository: EmployeeRepository). But You have many choices. when working in a team it should be better if everything is well organized.
As there are many thoughts on design pattern compare to repository/UnitOfWork patten, here is the standard implementation of repository & business layer.
***DATA LAYER***
namespace app.data
{
public interface IGenericDataRepository<T> where T : class
{
IList<T> GetAll(params Expression<Func<T, object>>[] navigationProperties);
IList<T> GetList(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties);
T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties);
void Add(params T[] items);
void Update(params T[] items);
void Remove(params T[] items);
}
}
namespace app.data
{
public class GenericDataRepository<T> : IGenericDataRepository<T> where T : class
{
public virtual IList<T> GetAll(params Expression<Func<T, object>>[] navigationProperties)
{
List<T> list;
using (var context = new GatePassEntities())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
list = dbQuery
.AsNoTracking()
.ToList<T>();
}
return list;
}
public virtual IList<T> GetList(Func<T, bool> where,
params Expression<Func<T, object>>[] navigationProperties)
{
List<T> list;
using (var context = new GatePassEntities())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
list = dbQuery
.AsNoTracking()
.Where(where)
.ToList<T>();
}
return list;
}
public virtual T GetSingle(Func<T, bool> where,
params Expression<Func<T, object>>[] navigationProperties)
{
T item = null;
using (var context = new GatePassEntities())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
item = dbQuery
.AsNoTracking() //Don't track any changes for the selected item
.FirstOrDefault(where); //Apply where clause
}
return item;
}
public virtual void Add(params T[] items)
{
using (var context = new GatePassEntities())
{
foreach (T item in items)
{
context.Entry(item).State = EntityState.Added;
}
context.SaveChanges();
}
}
public virtual void Update(params T[] items)
{
using (var context = new GatePassEntities())
{
foreach (T item in items)
{
context.Entry(item).State = EntityState.Modified;
}
context.SaveChanges();
}
}
public virtual void Remove(params T[] items)
{
using (var context = new GatePassEntities())
{
foreach (T item in items)
{
context.Entry(item).State = EntityState.Deleted;
}
context.SaveChanges();
}
}
}
}
//Domain Models like Employee, Department can be your objectcontext, dbcontext (can be generated by EF or other ORM Tools like T4)
namespace app.data
{
public interface IEmployeeRepository : IGenericDataRepository<Employee>
{
}
public interface IDepartmentRepository : IGenericDataRepository<Department>
{
}
}
***BUSINESS LAYER***
namespace app.business
{
public interface IBusinessLayer
{
IList<Employee> GetAllEmployees();
IList<Employee> GetEmployeesByCountryName(string countryName);
Employee GetEmployeeByName(string EmployeeName);
Employee GetEmployeeByIdentityId(int identityId, string EmployeeUniqueIdentityNumber);
void AddEmployee(params Employee[] Employees);
void UpdateEmployee(params Employee[] Employees);
void RemoveEmployee(params Employee[] Employees);
}
}
public class BuinessLayer : IBusinessLayer
{
private readonly IEmployeeRepository _EmployeeRepository;
public BuinessLayer()
{
_EmployeeRepository = new EmployeeRepository();
}
public BuinessLayer(IEmployeeRepository EmployeeRepository)
{
_EmployeeRepository = EmployeeRepository;
}
public IList<Employee> GetAllEmployees()
{
return _EmployeeRepository.GetAll();
}
public IList<Employee> GetEmployeesByCountryName(string countryName)
{
return _EmployeeRepository.GetList(e => e.Country.Employees.Equals(countryName));
}
public Employee GetEmployeeByName(string EmployeeName)
{
return _EmployeeRepository.GetSingle(
d => d.Name.Equals(EmployeeName),
d => d.Country); //include related employees
}
public Employee GetEmployeeByIdentityId(int identityId, string EmployeeUniqueIdentityNumber)
{
var EmployeeIdentity = _EmployeeIdentityRepository
.GetSingle
(
q => q.IdentityId == identityId && q.UniqueIdentityNumber == EmployeeUniqueIdentityNumber);
Employee Employee = new Employee();
if (EmployeeIdentity != null)
{
Employee = _EmployeeRepository.GetSingle(o => o.EmployeeId == EmployeeIdentity.EmployeeId);
}
else
Employee = null;
return Employee;
}
public void AddEmployee(params Employee[] Employees)
{
try
{
_EmployeeRepository.Add(Employees);
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
}
}
}
}
public void UpdateEmployee(params Employee[] Employees)
{
/* Validation and error handling omitted */
_EmployeeRepository.Update(Employees);
}
public void RemoveEmployee(params Employee[] Employees)
{
/* Validation and error handling omitted */
_EmployeeRepository.Remove(Employees);
}
}
Now you can call business layer from the front-end

Make a where or any clause in a IRepository pattern with entity framework

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.

Cant Instance from RepositoryPattern Class

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

Categories

Resources