Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

making a global filter for entity framework

For my models I have a active attribute on all of them, and i want to filter all inactive if the model was not displayed on the administration What is the best way to do that, What I'm currently using is the following

in my base model class i have this method that filters the collections

public virtual IQueryable<T> GlobalDefaultScope<T>(IQueryable<T> c) where T : CModel<T>
{
    if (settings.is_admin)
    {
        c = c.Where(m => m.active);
    }
    return c;
}

and on my model for every relation i did the following method

DbSet<T> set ...
var X = set.Where(some filter);
var list = globalDefaultScope(X).ToList();
return list;

And now I'm having some serious problems when i want to eagerly load some subrelations using include("Xmodel.Ymodel") i called the globalDefaultScope in the get method for that collection that filters the collection but it keeps throwing this exception when some items in the collection are inactive

System.InvalidOperationException: The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable.

how can i fix this or how can i make this filter in a more elegant way because i'm really not very satisfied of how i implemented it.

please ask for Any missing information or code blocks or any details

Update:

I also found this link, but this way didn't work with eagerly loaded entries (include())

Update2:

this is an example of how i use the include and where the error occurs

In My Model

public IQueryable<Dish> getSomeRelation(bool eagerly_load_sub_relation1, bool eagerly_load_sub_relation2)
        {
            var query = getQuery(...);
            //getQuery =>  query = db.Entry(obj).Collection(collection).Query() 
            //GlobalDefaultScope(query)
            if ( eagerly_load_sub_relation1){
                query = query.Include(m => m.sub_relation1);
            }
            if (eagerly_load_sub_relation2){
                query = query.Include("sub_relation2.sub_relation_of_sub_relation2");
            }
            return query;
        }

while i couldn't filter the relations in the include i did the following :

private ICollection<SubRelation1> _sub_relation1 {get; set;}
public ICollection<SubRelation1> sub_relation1 {
get 
{
   //something like:
   return GlobalDefaultScope(_sub_relation1 ).ToList(); 
}  
set;}

while we filter the results in sub_relation1, when i do db.SaveChanges() the mentioned error is thrown.

like image 693
Hilmi Avatar asked Sep 09 '13 21:09

Hilmi


People also ask

How do I filter data in Entity Framework?

To filter data, use linq. You can not use Filter property of BindingSource when the underlying list is BindingList<T> ; Only underlying lists that implement the IBindingListView interface support filtering. To remove filter, just set the data source of your binding source to the local storage of your entities again.

What is global query filter?

Global query filters are LINQ query predicates applied to Entity Types in the metadata model (usually in OnModelCreating ). A query predicate is a boolean expression typically passed to the LINQ Where query operator. EF Core applies such filters automatically to any LINQ queries involving those Entity Types.

What is Entity Framework Core?

Entity Framework (EF) Core is a lightweight, extensible, open source and cross-platform version of the popular Entity Framework data access technology. EF Core can serve as an object-relational mapper (O/RM), which: Enables . NET developers to work with a database using . NET objects.

Why Entity Framework?

The Entity Framework enables developers to work with data in the form of domain-specific objects and properties, such as customers and customer addresses, without having to concern themselves with the underlying database tables and columns where this data is stored.


2 Answers

You can create extension methods like

public static IQueryable<T> Where<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate)
{
    source = source.Where("isActive == true"); // From System.linq.Dynamic Library
    source = Queryable.Where<T>(source, predicate);
    return source;
}

and use them like

var user = db.UserProfiles.Include("webpages_Roles").Where(u => u.UserId < 30);

This should work, Please Let me know if you need more information.

Note : Please Add Nuget package for System.Linq.Dynamic to have dynamic Linq Library

Update 1:

I have included IsActive in webpages_Roles and UsreProfile table of simple membership and also included one more table Role Priority which refers to webpages_Roles, for easy to use I have changed the all the relation ships to one to many(from many to many). now if I use code similar to yours, extension method gives error when there is any user for which there are no roles.

If I give roles to every user and I have priority for every roles then this won't give error.

Please Let me know if you still need any other info.

Update 2

You can create one extension Method like

public static IQueryable<T> WhereActive<T>(this IQueryable<T> source)
        {
            return source.Where("isActive == true"); // From System.linq.Dynamic Library
        }

and call other methods like

var user = db.UserProfiles.Include("webpages_Roles").WhereActive().Where(u => u.UserId < 30);

or

var user = db.UserProfiles.Include("webpages_Roles").WhereActive().FirstOrDefault(u => u.UserId < 30);

Please Let me know if you still need any other info.

like image 57
5 revs, 2 users 92% Avatar answered Oct 18 '22 19:10

5 revs, 2 users 92%


You can do it like this:

  1. In OnModelCreating add an IsDeleted discriminator to every entity that can be soft deleted
  2. Override SaveChanges and find all the entries to be deleted
  3. Run SQL on these entries to set the IsDeleted discriminator then set their state to "detached"
  4. Change any unique indexes to ignore any soft deleted records

You can find working code at this answer: How to soft delete using Entity Framework Code First

like image 45
Colin Avatar answered Oct 18 '22 19:10

Colin