编辑此问题,希望更加清晰明了。
我们有一个Entity Framework Code First设置。为了举例说明,我简化了两个类,实际上还有大约10多个类类似于'Record',其中'Item'是导航属性/外键。
'Item'类:
public class Item
{
public int Id { get; set; }
public int AccountId { get; set; }
public List<UserItemMapping> UserItemMappings { get; set; }
public List<GroupItemMapping> GroupItemMappings { get; set; }
}
记录类:
public class Record
{
public int ItemId { get; set; }
public Item Item { get; set; }
}
this.User是一个注入到每个存储库中的用户对象,并包含在存储库基类中。 我们有一个以下代码的Item存储库:
this.User是注入到每个仓库中的用户对象,包含在仓库的基类中。我们有如下代码的Item仓库:
var items = this.GetAll()
.Where(i => i.AccountId == this.User.AccountId);
我在仓库基础上创建了以下表达式,以便轻松过滤数据(希望能够重复使用)。由于 LINQ to Entities 的工作原理,我们无法使用静态扩展方法(System.NotSupportedException "LINQ to Entities does not recognize the method X and this method cannot be translated into a store expression.")。
protected Expression<Func<Item, bool>> ItemIsOnAccount()
{
return item => item.AccountId == this.User.AccountId;
}
我已经解决了上述问题,方法如下:
var items = this.GetAll().Where(this.ItemIsOnAccount());
我们在该帐户内基于用户权限进行了额外的过滤(再次,这是另一种情况,我不想在我们拥有的每个代码库中重复此代码):
protected Expression<Func<Item, bool>> SubUserCanAccessItem()
{
return item => this.User.AllowAllItems
|| item.UserItemMappings.Any(d => d.UserId.Value == this.User.Id)
|| item.GroupItemMappings.Any(vm =>
vm.Group.GroupUserMappings
.Any(um => um.UserId == this.User.Id));
}
我可以按如下方式使用:
var items = this.GetAll().Where(this.SubUserCanAccessItem());
然而,在记录存储库中我们还需要一种解决以下问题的方法:
var records = this.GetAll()
.Where(i => i.Item.AccountId == this.User.AccountId);
由于“Item”是单个导航属性,我不知道如何将我创建的表达式应用到该对象。
我希望重用我在基于所有这些其他存储库创建的存储库中创建的表达式,以便我的“基于权限”的代码都在同一个位置,但是我不能简单地把它扔进去,因为这种情况下的Where子句是Expression<Func<Record,bool>>。
创建一个具有以下方法的接口:
Item GetItem();
因为LINQ to entities的原因,在其上进行操作并将其放在Record类中是行不通的。
我也不能创建一个基础抽象类并从中继承,因为除了需要过滤的Item之外,可能还有其他对象。例如,一个Record也可以有一个附加权限逻辑的'Thing'。并非所有对象都需要通过'Item'和'Thing'进行过滤,有些只需要一种,有些需要另一种,有些需要两种:
var items = this.GetAll()
.Where(this.ItemIsOnAccount())
.Where(this.ThingIsOnAccount());
var itemType2s = this.GetAll().Where(this.ThingIsOnAccount());
var itemType3s = this.GetAll().Where(this.ItemIsOnAccount());
由于这个问题只有一个父类是行不通的。
我是否可以重用我已经创建的表达式,或者至少创建一个表达式/修改原始表达式,使其在所有其他仓库中工作,当然,在这些仓库中,它们都返回自己的对象,但都具有导航到项目的属性?我需要如何修改其他仓库才能与这些仓库一起使用?
谢谢