为实体框架制作全局过滤器

时间:2013-09-09 21:14:29

标签: c# asp.net-mvc linq entity-framework

对于我的模型,我对所有模型都有一个active属性,如果模型没有在管理中显示,我想过滤所有非活动状态 最好的方法是什么,我目前使用的是以下

在我的基础模型类中,我有这个过滤集合的方法

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

在每个关系的模型上,我做了以下方法

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

现在我遇到了一些严重的问题,当我想用​​include("Xmodel.Ymodel")急切地加载一些子关系时我在globalDefaultScope方法中为get方法调用了过滤集合的集合但是当集合中的某些项目处于非活动状态时,它会不断抛出此异常

  

System.InvalidOperationException:     操作失败:因为一个或多个关系无法更改     外键属性是不可为空的。

我该如何解决这个问题,或者我怎样才能以更优雅的方式制作这个过滤器,因为我真的不太满意我是如何实现它的。

请询问任何遗漏的信息或代码块或任何细节

更新

我也发现了这个link,但这种方式不适用于急切加载的条目(include()

UPDATE2:

这是我如何使用包含和错误发生位置的示例

在我的模型中

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

虽然我无法过滤包含中的关系,但我执行了以下操作:

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

当我们在sub_relation1中过滤结果时,当我执行db.SaveChanges()时,会抛出提到的错误。

2 个答案:

答案 0 :(得分:6)

您可以创建

等扩展方法
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;
}

并像

一样使用它们
var user = db.UserProfiles.Include("webpages_Roles").Where(u => u.UserId < 30);

这应该有效,如果您需要更多信息,请告诉我。

注意:请为System.Linq.Dynamic添加Nuget包以获得动态Linq库

更新1:

我已将IsActive包含在webpages_Roles和UsreProfile简单成员资格表中,并且还包含一个表Role Intent,其中引用webpages_Roles,以便于使用我已将所有关系更改为一对多(从多对多) 。现在如果我使用类似于你的代码,当有任何没有角色的用户时,扩展方法会出错。

如果我为每个用户分配角色,并且我对每个角色都有优先权,那么这不会给出错误。

如果您还需要任何其他信息,请告诉我。

更新2

您可以创建一个类似

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

并调用其他方法,如

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

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

如果您还需要任何其他信息,请告诉我。

答案 1 :(得分:2)

你可以这样做:

  1. 在OnModelCreating中为每个可以软删除的实体添加一个IsDeleted鉴别器
  2. 覆盖SaveChanges并查找要删除的所有条目
  3. 在这些条目上运行SQL以设置IsDeleted鉴别器,然后将其状态设置为“已分离”
  4. 更改任何唯一索引以忽略任何软删除记录
  5. 您可以在此答案中找到工作代码: How to soft delete using Entity Framework Code First