I have a Generic Repository like below which handles my CRUD, for a single entity its easy to use, problem starts when i try to join my POCOs.
Lets say I have these POCO, they are mapped using fluent api (many to many and One to many relation) :
public class Student
{
public Student()
{
this.Courses = new HashSet<Course>();
}
public int StudentId { get; set; }
public string StudentName { get; set; }
//FKs
public virtual Standard Standard { get; set; }
public int StdandardRefId { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
public class Course
{
public Course()
{
this.Students = new HashSet<Student>();
}
public int CourseId { get; set; }
public string CourseName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Standard
{
public Standard()
{
Students = new List<Student>();
}
public int StandardId { get; set; }
public string Description { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
Mapping:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Many-To-Many
modelBuilder.Entity<Student>()
.HasMany<Course>(s => s.Courses)
.WithMany(c => c.Students)
.Map(cs =>
{
cs.MapLeftKey("StudentRefId");
cs.MapRightKey("CourseRefId");
cs.ToTable("StudentCourse");
});
//One-To-Many
modelBuilder.Entity<Student>()
.HasRequired<Standard>(s => s.Standard)
.WithMany(s => s.Students)
.HasForeignKey(s => s.StandardId);
}
Generic Repository:
public class Repository<T> : IRepository<T>
where T : class, IDisposable
{
internal MyDbContext context;
internal DbSet<T> dbSet;
public Repository()
{
context = new MyDbContext();
this.dbSet = context.Set<T>();
}
public bool Add(T entity)
{
var query = dbSet.Add(entity);
if (query != null)
return true;
return false;
}
public bool Update(T entity)
{
dbSet.Attach(entity);
var query = context.Entry(entity).State = EntityState.Modified;
if (query == EntityState.Modified)
return true;
return false;
}
public bool Delete(T entity)
{
var query = dbSet.Remove(entity);
if (query != null)
return true;
return false;
}
public bool Delete(Guid id)
{
var query = dbSet.Remove(dbSet.Find(id));
if (query != null)
return true;
return false;
}
public T GetById(Guid id)
{
var query = dbSet.Find(id);
if (query != null)
return query;
else
return null;
}
public ICollection<T> GetAll()
{
return dbSet.AsEnumerable<T>().ToList();
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
if (context != null)
{
context.Dispose();
context = null;
}
}
}
Now if i want to join Standard to Many-to-Many Table how may i be able to do this?
So based on your edit, I'm assuming you would like to join Students and Standards.
The first thing you have to do is change the repository so that it doesn't instantiate the context. You should pass that in as a parameter and store a reference to it:
public Repository(MyDbContext myCtx)
{
context = myCtx;
this.dbSet = context.Set<T>();
}
The second thing you have to do is change your repository to change the GetAll() method to return IQueryable<T> instead of ICollection<T>.
Then change the implementation of GetAll():
return dbSet;
This way you only get back a query and not the evaluated list of all the entities. And then you can do the join with the GetAll() method of the repositories just like you would do it with the db sets:
using (MyDbContext ctx = new MyDbContext())
{
var studentRep = new Repository<Student>(ctx);
var standardRep = new Repository<Standard>(ctx);
var studentToStandard = studentRep.GetAll().Join(standardRep.GetAll(),
student => student.StandardRefId,
standard => standard.StandardId,
(stud, stand) => new { Student=stud, Standard=stand }).ToList();
}
With this you get an IQueryable<T> in studentToStandard, which will run in the database once you call ToList() on it. Note that you have to pass in the same context to both of the repositories in order for this to work.
I recommend that you check out the Unit Of Work design pattern as well. It helps a lot when dealing with multiple repositories.
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
This is a more structured and better maintainable way of handling transactions when it comes to multiple entity sets, and promotes better separation of concerns.
Hope I understood your problem correctly and this helps.
I took this query where I was using Entity Framework
var result = (from metattachType in _dbContext.METATTACH_TYPE
join lineItemMetattachType in _dbContext.LINE_ITEM_METATTACH_TYPE on metattachType.ID equals lineItemMetattachType.METATTACH_TYPE_ID
where (lineItemMetattachType.LINE_ITEM_ID == lineItemId && lineItemMetattachType.IS_DELETED == false
&& metattachType.IS_DELETED == false)
select new MetattachTypeDto()
{
Id = metattachType.ID,
Name = metattachType.NAME
}).ToList();
and changed it into this where I'm using the repository pattern
Linq
return await _attachmentTypeRepository.GetAll().Where(x => !x.IsDeleted)
.Join(_lineItemAttachmentTypeRepository.GetAll().Where(x => x.LineItemId == lineItemId && !x.IsDeleted),
attachmentType => attachmentType.Id,
lineItemAttachmentType => lineItemAttachmentType.MetattachTypeId,
(attachmentType, lineItemAttachmentType) => new AttachmentTypeDto
{
Id = attachmentType.Id,
Name = attachmentType.Name
}).ToListAsync().ConfigureAwait(false);
Linq-to-sql
return (from attachmentType in _attachmentTypeRepository.GetAll()
join lineItemAttachmentType in _lineItemAttachmentTypeRepository.GetAll() on attachmentType.Id equals lineItemAttachmentType.MetattachTypeId
where (lineItemAttachmentType.LineItemId == lineItemId && !lineItemAttachmentType.IsDeleted && !attachmentType.IsDeleted)
select new AttachmentTypeDto()
{
Id = attachmentType.Id,
Name = attachmentType.Name
}).ToList();
Also, please know that Linq-to-Sql is 14x faster than Linq...
Related
I have this repository implementation:
using mediere_API.DataLayer.Entities;
using mediere_API.DataLayer.Repository.Interfaces;
using Microsoft.EntityFrameworkCore;
namespace mediere_API.DataLayer.Repository.Implementations
{
public class RepositoryBase<T> : IDisposable, IRepositoryBase<T> where T : BaseEntity, new()
{
private readonly DbContext _db;
private readonly DbSet<T> _dbSet;
protected RepositoryBase(EfDbContext context)
{
_db = context;
_dbSet = context.Set<T>();
}
public async Task<IList<T>> GetAll(bool asNoTracking = false, bool includeDeleted = false)
{
var query = includeDeleted
? _dbSet
: _dbSet.Where(entity => entity.DeletedAt == null);
return asNoTracking
? await query.AsNoTracking().ToListAsync()
: await query.ToListAsync();
}
public async Task<T> GetById(int id, bool asNoTracking = false, bool includeDeleted = false)
{
return includeDeleted
? await GetRecords(asNoTracking).FirstOrDefaultAsync(e => e.Id == id)
: await GetRecords(asNoTracking).FirstOrDefaultAsync(e => e.Id == id && e.DeletedAt == null);
}
public virtual void Insert(T record)
{
if (_db.Entry(record).State == EntityState.Detached)
{
_db.Attach(record);
_db.Entry(record).State = EntityState.Added;
}
}
public virtual void Update(T record)
{
if (_db.Entry(record).State == EntityState.Detached)
_db.Attach(record);
_db.Entry(record).State = EntityState.Modified;
}
public void Delete(T record)
{
if (record != null)
{
record.DeletedAt = DateTime.UtcNow;
Update(record);
}
}
public void Dispose()
{
_db?.Dispose();
}
protected IQueryable<T> GetRecords(bool asNoTracking = false, bool includeDeleted = false)
{
var result = includeDeleted ?
_dbSet
:
_dbSet.Where(e => e.DeletedAt == null);
return asNoTracking ? result.AsNoTracking() : result;
}
}
}
Let's say I have this Entity
using mediere_API.Dtos;
using System.ComponentModel.DataAnnotations;
namespace mediere_API.DataLayer.Entities
{
public class Localitate : BaseEntity
{
[Required]
public string Nume { get; set; }
[Required]
public int JudetId { get; set; }
public virtual Judet judet { get; set; }
public Localitate() { }
}
}
I observed that I don't get the foreign keys in my objects.
In order to get all the objects with their FKs, I decided to add this this method in the repository for that collection:
public async Task<List<Localitate>> GetLocalitatiBasicAsync()
{
return await base.GetRecords(true).Select(l => new Localitate()
{
Id = l.Id,
Nume = l.Nume,
judet = l.judet
}).ToListAsync();
}
Is this the best solution? And what would be the difference between using this select with judet too vs using the .include() method to include judet?
Thanks.
I have the below entity which has a navigation property.
public class Member
{
public Member()
{
Id = 0;
IsActive = true;
BillDetails = new List<BillDetail>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsActive { get; set; }
public int? OrgId { get; set; }
public IList<BillDetail> BillDetails { get; set; }
}
And I have a generic repository which is:
public abstract class BaseRepository<TEntity, TId> : IRepository<TEntity, TId> where TEntity : class
{
private readonly IApplicationDbContext _db;
public BaseRepository(IApplicationDbContext db)
{
_db = db;
}
public virtual void Add(TEntity entity)
{
_db.Set<TEntity>().Add(entity);
_db.Entry(entity).State = EntityState.Added;
}
public virtual bool Update(TEntity entity)
{
_db.Set<TEntity>().Attach(entity);
_db.Entry(entity).State = EntityState.Modified;
return true;
}
public virtual bool Delete(TEntity entity)
{
_db.Set<TEntity>().Remove(entity);
_db.Entry(entity).State = EntityState.Deleted;
return true;
}
public virtual IQueryable<TEntity> Query()
{
return _db.Set<TEntity>().AsQueryable();
}
public virtual EntityEntry<TEntity> Entry(TEntity entity)
{
return _db.Entry(entity);
}
public void Attach(TEntity entity)
{
if (entity == null || _db.Entry(entity).State != EntityState.Detached)
return;
_db.Set<TEntity>().Attach(entity);
}
public void Detach(TEntity entity)
{
if (entity == null)
return;
_db.Entry(entity).State = EntityState.Detached;
}
public abstract Task<TEntity> FindAsync(TId id);
}
From my service class I want to get collection of objects of below type
public class MemberBill
{
public int MemberId {get; set;}
public decimal BillAmount {get; set;}
}
In my service class I have the following query. Now How can I get the list of objects (MemberBill) from the below query?
var query = (_memberRepository.Query().Where(x => x.IsActive == true && x.OrgId == orgId)
.Include(x => x.BillDetails.Where(y => y.IsActive == true))).AsNoTracking().AsQueryable();
List<IList<BillDetail>> memberBills = query.Select(x => x.BillDetails).ToList();
memberBills.Select(x => new MemberBill
{
MemberId = x.
}).ToList();
Please help me to find the solution.
try this
var query = _memberRepository.Query()
.Where(x => x.IsActive == true && x.OrgId == orgId)
.Include(x => x.BillDetails.Where(y => y.IsActive == true))
.AsNoTracking()
.ToList();
var memberBills=new List<MemberBill>();
foreach(var m in query)
{
memberBills.Add( new MemberBill
{
MemberId= m.Id,
BillAmount=m.BillDetails.Sum(i=> i.Amount)
});
}
Leaving here performant solution. Current accepted answer uses a lot of memory and server resources.
var query =
from m in _memberRepository.Query()
where m => m.IsActive == true && m.OrgId == orgId
from bd in m.BillDetails.Where(bd => bd.IsActive == true)
group bd by new { m.Id } into g
select new MemberBill
{
MemberId = g.Key.Id,
BillAmount = g.Sum(x => x.Amount
};
var memberBills = query.ToList();
I have the following situation.
I'm building a course management MVC site where I have courses but also course iterations I call them as it happens sometime that a new student will join just for one iteration.
I have a model courseIterations which possess a ICollection of students. When starting the course I want to generate the next nine iterations with default students which subscribed to the course. The problem I have is that when I list the iterations the students where not saved. What am I doing wrong? Or is there a better approach in general?
public class CourseIteration : AuditableEntity<int>
{
public Course Course { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Date")]
public DateTime Date { get; set; }
public virtual ICollection<Student> Students { get; set; }
public virtual ICollection<Instructor> Instructors { get; set; }
}
My attempt to fill
private void FillIterations(Course course, int coursePeriod)
{
var defaultStudents = _studentRepository.GetAllByCourse(course.CourseID).ToList(); // load the existing Items
course.Iterations = new List<CourseIteration>();
for (int i = 0; i < coursePeriod; i++)
{
var item = new CourseIteration
{
Course = course,
Date = course.StartDate.AddDays(i * 7),
Instructors = course.Instructors,
Students = new List<Student>()
};
foreach (var student in defaultStudents)
{
item.Students.Add(student);
}
_courseIterationRepository.Add(item);
course.Iterations.Add(item);
_courseIterationRepository.Save();
_courseRepository.Save();
}
}
I use a Generic Repository
public abstract class GenericRepository : IGenericRepository
where T : BaseEntity
{
protected DbContext _entities;
protected readonly IDbSet _dbset;
public GenericRepository(DbContext context)
{
_entities = context;
_dbset = context.Set<T>();
}
public virtual IEnumerable<T> GetAll()
{
return _dbset.AsEnumerable<T>();
}
public IEnumerable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
IEnumerable<T> query = _dbset.Where(predicate).AsEnumerable();
return query;
}
public virtual T Add(T entity)
{
return _dbset.Add(entity);
}
public virtual T Attach(T entity)
{
return _dbset.Attach(entity);
}
public virtual T Delete(T entity)
{
return _dbset.Remove(entity);
}
public virtual void Edit(T entity)
{
_entities.Set<T>().Attach(entity);
_entities.Entry(entity).State = EntityState.Modified;
Save();
}
public virtual void Save()
{
_entities.SaveChanges();
}
Custom Save function could be the problem?
public override int SaveChanges()
{
var modifiedEntries = ChangeTracker.Entries()
.Where(x => x.Entity is IAuditableEntity
&& (x.State == System.Data.Entity.EntityState.Added || x.State == System.Data.Entity.EntityState.Modified));
foreach (var entry in modifiedEntries)
{
IAuditableEntity entity = entry.Entity as IAuditableEntity;
if (entity != null)
{
string identityName = Thread.CurrentPrincipal.Identity.Name;
DateTime now = DateTime.UtcNow;
if (entry.State == System.Data.Entity.EntityState.Added)
{
entity.CreatedBy = identityName;
entity.CreatedDate = now;
}
else
{
base.Entry(entity).Property(x => x.CreatedBy).IsModified = false;
base.Entry(entity).Property(x => x.CreatedDate).IsModified = false;
}
entity.UpdatedBy = identityName;
entity.UpdatedDate = now;
}
}
return base.SaveChanges();
}
I'm trying to do a generic Db cotext helper\manager so I can use it as a dll in many projects with different data bases.
I tried to use it with one of my projects but I got confused with the attach and detach in the Add and Edit methods. I'm getting errors as "An entity object cannot be referenced by multiple instances of IEntityChangeTracker."
Could someone help me to get this manager perfect?
public class DbEntityManager<T> : IDisposable where T : class, IEntity
{
public DbContext DbEntities { get; set; }
public virtual int AddNewObject(T objToAdd)
{
DbEntities.Set<T>().Add(objToAdd);
return DbEntities.SaveChanges();
}
public virtual int EditObject(T objToEdit)
{
if (DbEntities.Entry(objToEdit).State == EntityState.Detached)
{
DbEntities.Set<T>().Attach(objToEdit);
DbEntities.Entry(objToEdit).State = EntityState.Modified;
}
else
{
DbEntities.Entry(objToEdit).State = EntityState.Modified;
}
return DbEntities.SaveChanges();
}
public virtual int DeleteObject(T objToDelete)
{
DbEntities.Set<T>().Remove(objToDelete);
return DbEntities.SaveChanges();
}
public virtual List<T> GetAllList()
{
return DbEntities.Set<T>().ToList();
}
public virtual T GetObjectById(int id)
{
return DbEntities.Set<T>().AsEnumerable().SingleOrDefault(x => x.Id == id);
}
public DbEntityManager(DbContext db)
{
DbEntities = db;
}
public void Dispose()
{
this.Dispose();
}
}
EDIT: Trying to explain better what I'm reffering.
The IEntity is an interface just to be able to use the GetObjectById function:
public interface IEntity
{
int Id { get; }
}
Here is an example of a class:
public partial class Address : IEntity
{
public Address()
{
this.Customers = new HashSet<Customer>();
}
public int AddressID { get; set; }
public string Address_Country { get; set; }
public string Address_City { get; set; }
public string Address_Street { get; set; }
public string Address_ZipCode { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
public int Id
{
get { return AddressID; }
}
}
So I can use the code like this: Making a manager just for the class
public class AddressManager : DbEntityManager<Address>
{
public AddressManager()
: base (new MySystemEntities())
{
}
}
And then use it the code (in winform/mvc or whatever):
AddressManager manager = new AddressManager ();
Address address = new Address();
address = manager.GetObjectById(id);
Or:
Address address = new Address();
address.Address_Country = "USA";
manager.AddNewObject(address);
Before I did this I searched the internet to see if a class like this already exist, but I didn't find any. So if anyone knows a class already made with these functions I'd be glad to use it.
I have generally used the Repository along with the UnitOfWork pattern.
Try implementing such a base repository and then created derived entity types using the same.
That will help keep your code DRY.
public interface IBaseRepository<TEntity> : IDisposable
where TEntity : class
{
void Delete(object id);
void Delete(TEntity entity);
TEntity Find(params object[] keyValues);
void Insert(TEntity entity);
void InsertRange(IEnumerable<TEntity> entities);
IQueryable<TEntity> SelectQuery(string query, params object[] parameters);
void Update(TEntity entity);
void RefreshEntityContext(TEntity entity);
}
Hope this helps!
Edit: Ok, here is an extract of the implementation (similar to how I have implemented it):
namespace ContosoUniversity.DAL
{
public class GenericRepository<TEntity> where TEntity : class
{
internal SchoolContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(SchoolContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
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;
}
}
}
You can now inherit your repositories from the GenericRepository and have all the basic CRUD operations available.
from,
http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
I prefer to do something like the following:
public virtual int EditObject(T objToEdit)
{
var curval = DB.Set<T>().FirstOrDefault(x => x.Id == objToEdit.Id);
//You may want to make all your entities inherit from the same
//baseclass to get Id
if (curval == null)
{
DB.Set<T>.Add(objToEdit);
}
else
{
DB.Entry(curval).CurrentValues.SetValues(objToEdit);
DB.Entry(curval).State = System.Data.Entity.EntityState.Modified;
}
return DB.SaveChanges();
}
it's quite easy to modify this code to work with Models too.
Why reinvent the wheel. Try NRepository, it's a generic repository (yes, another one) with an entity framework extension and uses strategies for reuse rather then service methods.Plus its fully testable without mocks.
IQueryRepository queryRepository = new EntityFrameworkQueryRepository(new YourDbContext()) ;
var address = queryRepository.GetEntity<Address>(
p => p.AddressID == 2,
new AsNoTrackingQueryStrategy(),
new EagerLoadingQueryStrategy<Address>(
p => p.Customers));
Or to add entities as well as just use :
IRepository repository = new EntityFrameworkRepository(new YourDbContext()) ;
var address = new Address{ Address_City = "Leeds" };
repository.Add(address);
repository.Save()
N.B. Don't forget to inject in your repositories :)
entity framework already use repository and unit of work design pattern, no need for an helpers to work with that framework
I have create a Generic Repository (Using EF 6.1.1), which I am using in several projects and it works very well.
I have implemented a 'soft' delete feature, where we mark data as deleted, but do not actually remove it from the database.
I can then filter all my queries as all entities inherit from a base entity which has the IsDeleted property. This is all works nicely, but it obviously does not filter out any of the 'soft deleted' child entities.
I am unsure how to go about doing this in a generic way, as I dont want to have to over code a solution into every respoitory, that really defeats the reason for having a generic repo.
this is an example of my current Generic Repo
public sealed class MyRepository<T> : IRepository<T> where T : BaseEntity
{
public String CurrentUser { get; set; }
private readonly MyObjectContext context;
private readonly Configuration configuration = ConfigurationManager.GetConfiguration();
private IDbSet<T> entities;
private IDbSet<T> Entities
{
get { return entities ?? (entities = context.Set<T>()); }
}
public MyRepository(MyObjectContext context, String userName = null)
{
this.context = context;
var providerManager = new DataProviderManager(configuration);
var dataProvider = (IDataProvider)providerManager.LoadDataProvider();
dataProvider.InitDatabase();
CurrentUser = userName;
}
public void Dispose()
{
//do nothing at the moment
}
public T GetById(Guid id)
{
return Entities.FirstOrDefault(x => x.Id == id && !x.IsDeleted);
}
public IQueryable<T> GetAll()
{
return Entities.Where(x => !x.IsDeleted);
}
public IQueryable<T> Query(Expression<Func<T, bool>> filter)
{
return Entities.Where(filter).Where(x => !x.IsDeleted);
}
public void Delete(T entity)
{
if (configuration.HardDelete)
{
HardDelete(entity);
}
else
{
SoftDelete(entity);
}
}
private void HardDelete(T entity)
{
try
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
Entities.Attach(entity);
Entities.Remove(entity);
}
catch (DbEntityValidationException ex)
{
var msg = string.Empty;
foreach (var validationErrors in ex.EntityValidationErrors)
foreach (var validationError in validationErrors.ValidationErrors)
msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
var fail = new Exception(msg, ex);
throw fail;
}
}
private void SoftDelete(T entity)
{
entity.IsDeleted = true;
Update(entity);
}
}
Any help on this would be great.
Thanks
Someone has built a global filter, you can try it and install it from nuget EntityFramework.Filters.
https://github.com/jbogard/EntityFramework.Filters
Here is an example how to use it.
public abstract class BaseEntity
{
public int Id { get; set; }
public bool IsDeleted { get; set; }
}
public class Foo : BaseEntity
{
public string Name { get; set; }
public ICollection<Bar> Bars { get; set; }
}
public class Bar : BaseEntity
{
public string Name { get; set; }
public int FooId { get; set; }
public Foo Foo { get; set; }
}
public class AppContext : DbContext
{
public DbSet<Foo> Foos { get; set; }
public DbSet<Bar> Bars { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Registers and configures it first.
DbInterception.Add(new FilterInterceptor());
var softDeleteFilter = FilterConvention.Create<BaseEntity>("SoftDelete",
e => e.IsDeleted == false); // don't change it into e => !e.IsDeleted
modelBuilder.Conventions.Add(softDeleteFilter);
}
}
Then you can enable it in your repository constructor or somewhere after db context instance is created because the filters are disabled by default.
using (var db = new AppContext())
{
db.EnableFilter("SoftDelete");
var foos = db.Foos.Include(f => f.Bars).ToArray(); // works on Include
}
using (var db = new AppContext())
{
db.EnableFilter("SoftDelete");
var foos = db.Foos.ToArray();
foreach (var foo in foos)
{
var bars = foo.Bars; // works on lazy loading
}
}
using (var db = new AppContext())
{
db.EnableFilter("SoftDelete");
var foos = db.Foos.ToArray();
foreach (var foo in foos)
{
db.Entry(foo).Collection(f => f.Bars).Load(); // works on manual loading
}
}
This filter is not needed anymore.
public IQueryable<T> Query(Expression<Func<T, bool>> filter)
{
return Entities.Where(filter);//.Where(x => !x.IsDeleted);
}
As long as you have enabled it.
public MyRepository(MyObjectContext context, String userName = null)
{
this.context = context;
if (!configuration.HardDelete)
{
this.context.EnableFilter("SoftDelete");
}
}
I was having the same problem but my method to solve was little different i used a genric base interface IGenricInterface with IsDeleted as property
public int DeletebyId(string Id)
{
var Ent = (IGenricInterface)_sitecontext.Set<TEntity>().Find(Id);
Ent.IsDeleted = 1;
}
and for hardDelete
_sitecontext.Set<TEntity>().Remove(Ent);
This is on ID but offcourse you can do it on EnTity as well