为entity framework制作全局filter
对于我的模型,我在所有模型上都有一个active
属性,如果管理中没有显示模型,我想过滤所有非活动状态。最好的方法是什么,我目前使用的是以下内容
在我的基础模型类中,我有这个过滤集合的方法
public virtual IQueryable GlobalDefaultScope(IQueryable c) where T : CModel { if (settings.is_admin) { c = c.Where(m => m.active); } return c; }
在我的每个关系的模型上,我做了以下方法
DbSet set ... var X = set.Where(some filter); var list = globalDefaultScope(X).ToList(); return list;
现在我有一些严重的问题,当我想急切地使用include("Xmodel.Ymodel")
加载一些子关系时,我在该集合的get
方法中调用了globalDefaultScope
来过滤集合,但它在某些项目时不断抛出此exception在集合中是不活动的
System.InvalidOperationException:操作失败:无法更改关系,因为一个或多个外键属性不可为空。
我怎么能解决这个问题,或者我怎么能以更优雅的方式制作这个filter,因为我真的不太满意我是如何实现它的。
请询问任何遗漏的信息或代码块或任何细节
更新:
我也找到了这个链接 ,但这种方式不适用于急切加载的条目( include()
)
UPDATE2:
这是我如何使用包含和错误发生的示例
在我的模型中
public IQueryable 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 _sub_relation1 {get; set;} public ICollection sub_relation1 { get { //something like: return GlobalDefaultScope(_sub_relation1 ).ToList(); } set;}
当我们在sub_relation1中过滤结果时,当我执行db.SaveChanges()时,会抛出上述错误。
您可以创建类似的扩展方法
public static IQueryable Where (this IQueryable source, Expression> predicate) { source = source.Where("isActive == true"); // From System.linq.Dynamic Library source = Queryable.Where (source, predicate); return source; }
并使用它们
var user = db.UserProfiles.Include("webpages_Roles").Where(u => u.UserId < 30);
这应该工作,如果您需要更多信息,请告诉我。
注意:请为System.Linq.Dynamic添加Nuget包以获得动态Linq库
更新1:
我已经将webAages_Roles和UsreProfile表中的IsActive包含在简单成员资格中,还包括一个表格Role Priority,它指的是webpages_Roles,为了便于使用我已经将所有关系变为一对多(从多对多)。 现在如果我使用类似于你的代码,当有任何没有角色的用户时,扩展方法会出错。
如果我给每个用户赋予角色,并且我对每个角色都有优先权,那么这不会给出错误。
如果您还需要任何其他信息,请告诉我。
更新2
您可以创建一个扩展方法
public static IQueryable WhereActive (this IQueryable 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);
如果您还需要任何其他信息,请告诉我。
你可以这样做:
- 在OnModelCreating中,为每个可以被软删除的实体添加一个IsDeleted鉴别器
- 覆盖SaveChanges并查找要删除的所有条目
- 在这些条目上运行SQL以设置IsDeleted鉴别器,然后将其状态设置为“已分离”
- 更改任何唯一索引以忽略任何软删除的记录
您可以在此答案中找到工作代码: 如何使用Entity Framework Code First进行软删除