【问题标题】:making a global filter for entity framework为实体框架制作全局过滤器
【发布时间】:2013-09-09 21:14:28
【问题描述】:

对于我的模型,我在所有模型上都有一个 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") 急切地加载一些子关系时,我遇到了一些严重的问题集合中的某些项目处于非活动状态

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

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

请询问任何缺失的信息或代码块或任何细节

更新:

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

更新2:

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

在我的模型中

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() 时,会抛出上述错误。

【问题讨论】:

  • 如果您在不应用过滤器的情况下执行 include() 是否有效,即错误是否消失。你能展示一些如何应用包含的代码吗?
  • @TommyGrovnes 问题已更新,谢谢。
  • @Hilmi 你能否也包括数据库表。(我觉得对于你的第一个关系,你没有得到值,因为可能没有任何数据,你正在尝试获得 null 的第二个关系船
  • 尝试在实体 REST SDK entityrestsdk.codeplex.com 中指定的 SecurityContext

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


【解决方案1】:

您可以创建扩展方法,例如

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:

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

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

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

更新 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);

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

【讨论】:

  • 先生,使用这种方式会有问题,因为您覆盖了 Where 函数,并且在我的代码中我使用 Where First FirstOrDefault ... 和许多其他函数,我将不得不循环它们并覆盖它们,如果我错过任何理解的事情,请告诉我,非常感谢先生
  • 非常感谢先生,您的方式很好,但我必须走遍整个网站并在他们身上调用WhereActive 方法,我将等待找到更集中的自我控制方式来做到这一点,如果我没有找到任何东西(我似乎不会),我会选择并将您的答案标记为已选择的答案。再次感谢
  • 我认为,创建(和推广)一个库,它也会让你失去属性的强类型,而不是仅仅创建一个带有 bool IsActive 属性的 IActivatedEntity 接口并设置类型约束where T : IActivatedEntityWhereActive() 扩展方法并将该接口应用于您的实体,有点远恕我直言。
【解决方案2】:

你可以这样做:

  1. 在 OnModelCreating 中为每个可以软删除的实体添加一个 IsDeleted 鉴别器
  2. 覆盖 SaveChanges 并找到所有要删除的条目
  3. 对这些条目运行 SQL 以设置 IsDeleted 鉴别器,然后将它们的状态设置为“分离”
  4. 更改任何唯一索引以忽略任何软删除记录

您可以在此答案中找到工作代码: How to soft delete using Entity Framework Code First

【讨论】:

  • 我想这正是我想要的!但现在它不能使用预先生成的视图,我会寻找解决方案,非常感谢先生
  • 你怎么能先使用数据库做同样的事情,或者为什么不可能?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-08
  • 2015-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多