Add filter to all query entity framework

前端 未结 4 1552
孤街浪徒
孤街浪徒 2020-12-18 11:07

I want add CompanyID filter to my all entity framework request.Because each user must see just their records.I dont want add filter (x=>x.CompanyID == cID) all methods in bu

相关标签:
4条回答
  • 2020-12-18 11:45

    You can also extend the object context and add an extension method that returns IQueryable

    Like

    public class CustomdbContext : DbContext
    {       
        public IQueryable<TEntity> ApplyCustomerFilter<TEntity>(IQueryable<TEntity> query) where TEntity : Customer 
        {
             return query.Where(x => x.CustomerId == customerctxId);
        }
    }
    
    0 讨论(0)
  • 2020-12-18 11:46

    You can implement IHasCompanyId interface in such entities. And then implement repository pattern as:

    public class MyRepository<T>
    {
        public MyRepository(DbContext dbContext, int companyID)
        {
            if (dbContext == null) 
                throw new ArgumentNullException("Null DbContext");
            DbContext = dbContext;
            DbSet = DbContext.Set<T>();
    
            CompanyID = companyID;
        }
    
        protected DbContext DbContext { get; set; }
        protected int CompanyID  { get; set; }
    
        protected DbSet<T> DbSet { get; set; }
    
        // Add filter here
        public virtual IQueryable<T> GetAll()
        {
            if(typeof(IHasCompanyID).IsAssignableFrom(typeof(T)))
                return DbSet.Where(x => x.CompanyID == CompanyID);
            else 
                return DbSet;
        }
    }
    

    And initialize _financeDal as:

    var _financeDal = new MyRepository<TEntity>(dbContext, companyID);
    
    0 讨论(0)
  • 2020-12-18 11:48

    In the Entity Framework Core 2.0, you can use Global Query Filters.

    1. Add filter just to the one entity:

      public interface IDelete
      {
          bool IsDeleted { get; set; }
      }
      
      public class Blog : IDelete
      {        
          public int BlogId { get; set; }
          public string Name { get; set; }
          public string Url { get; set; }
      
          public List<Post> Posts { get; set; }
      }
      
      public class Post : IDelete
      {
          public int PostId { get; set; }
          public string Title { get; set; }
          public string Content { get; set; }
          public bool IsDeleted { get; set; }
      
          public int BlogId { get; set; }
          public Blog Blog { get; set; }
      }
      
      // Default method inside the DbContext or your default Context
      protected override void OnModelCreating(ModelBuilder modelBuilder)
      {         
          base.OnModelCreating(builder);  
      
          modelBuilder.Entity<Blog>()
                      // Add Global filter to the Blog entity
                      .HasQueryFilter(p => p.IsDeleted == false);
      
          modelBuilder.Entity<Post>()
                      // Add Global filter to the Post entity
                      .HasQueryFilter(p => p.IsDeleted == false);
      }
      
    2. If you have many entities, the first way isn't good, Use below code for applying the global filter to all entities(Magic way):

      public static class ModelBuilderExtension
      {
          public static void ApplyGlobalFilters<TInterface>(this ModelBuilder modelBuilder, Expression<Func<TInterface, bool>> expression)
          {
              var entities = modelBuilder.Model
                  .GetEntityTypes()
                  .Where(e => e.ClrType.GetInterface(typeof(TInterface).Name) != null)
                  .Select(e => e.ClrType);
              foreach (var entity in entities)
              {
                  var newParam = Expression.Parameter(entity);
                  var newbody = ReplacingExpressionVisitor.Replace(expression.Parameters.Single(), newParam, expression.Body);    
                  modelBuilder.Entity(entity).HasQueryFilter(Expression.Lambda(newbody, newParam));
              }
          }
      }
      
      // Default method inside the DbContext or your default Context
      protected override void OnModelCreating(ModelBuilder builder)
      {
          base.OnModelCreating(builder);
      
          modelBuilder.Entity<Blog>();
          modelBuilder.Entity<Post>();
      
          builder.ApplyGlobalFilters<IDelete>(e => e.IsDeleted == false);
      }
      

    And Queries will be:

        exec sp_executesql N'SELECT [x].[BlogId], [x].[Name], [x].[Url]
        FROM [dbo].[Blog] AS [x]
        WHERE [x].[IsDeleted] = 0'
    
    0 讨论(0)
  • 2020-12-18 11:56

    everything you suggest does not work for the following scenario: HasQueryFilter power, but per each HTTP request. ApplyGlobalFilters / OnModelCreating applied once for model creation. But if you reload the page with different request parameters - they won't be taken into account to filter out DbSet. If you add the filter to GetAll call - another call 'Include'-ing the entity won't have this filter. We need real global mechanism to filter out DbSets by specific condition - which may change per each request (page refresh).

    0 讨论(0)
提交回复
热议问题