可以在linq中执行此操作吗?

时间:2011-03-21 22:57:08

标签: c# linq

我想知道这样的事情是否可以完成(当然我所写的内容不起作用,但这正是我本来想要实现的目标)。

var test = u.Owner;
a.Table.Where(u => test == true)

我有一个我要重用的linq查询(基本上我得到了一个我使用了5次的查询),唯一改变的是我正在比较的内容。

所以在上面的u.Owner与真实比较。在另一个查询中,它看起来是一样的,但不是u.Owner,我可能有u.Add == true或u.Edd == true。

有没有一种方法可以重用我所拥有的东西。当然,在我的代码中,查询有点长,但我只是缩短了。

修改

基本上是整个查询

 List<Permission> clearence = user.PermissionLevels.Where(u => u.Id == Id &&( u.Add == permissionNeeded || u.Permission.Name == PermissionTypes.Owner)).ToList();

permissionNeeded == Enum

所以我的原始方式是u.Permission.Name == permissionNeeded所以我将枚举值与字符串进行了比较。

现在我的数据库模型已经发生变化,我需要分别检查5个不同的权限,这些权限是bool而不是字符串。

u.Add = true || u.Owner == true;
u.Edit = true || u.Owner == true;
u.Delete= true || u.Owner == true;
u.View= true || u.Owner == true;

这是整个查询的所有更改,这就是为什么我想把它变成一个查询(就像我以前一样)。

所以我想有一个switch语句。该方法仍然接受permissionNeeded(enum)然后我会查看我需要的子句以及如何将其插入查询中。

switch(PermssionNeeded)
{
   case PermissionTypes.Add:
                            u.Add;
                            break;
  // all other cases here.
}

4 个答案:

答案 0 :(得分:4)

利用Where可以使用类型Table作为参数的任何函数并返回布尔值来创建类似函数的事实:

public IQueryable<Table> QueryTables(Func<Table, bool> testFunction)
{
    return a.Table.Where(testFunction).AsQueryable<Table>();
}

编辑(除了编​​辑以添加上面的AsQueryable,我之前忘记了)

如果 all 你要做的是改变测试中使用的布尔字段,你不想指定一个完整的函数(你要发现的很多)更容易),你需要使用一些反思:

using System.Reflection;

public IQueryable<Table> QueryTables(PropertyInfo pi)
{
    return a.Table.Where(t => (bool)(pi.GetGetMethod().Invoke(t, null))).AsQueryable<Table>();
}

要构造PropertyInfo对象,请使用以下内容:

PropertyInfo pi = typeof(Table).GetProperty("Owner");

我更喜欢早期的方法,但我确实想表明这样的事情至少是可能的。

答案 1 :(得分:3)

如果您只想指定要检查的属性,可以执行

public IEnumerable<Table> GetTables(Func<Table,bool> getValue)
{
    return a.Table.Where(table => /*some common filter*/)
                  .Where(table => getValue(table))
}

答案 2 :(得分:1)

var query = from u in uSrc join v in vSrc on u.ID equals v.RelatedUID
  where v.Valid && u.Created < DateTime.UtcNow.AddDays(-365)
  select u; // relatively complicated starting point.
var q1 = query.Where(u => u.Add); // must also have Add true
var q2 = query.Where(u => u.Test); // must also have Test true
var q3 = query.Where(u => u.ID < 50); // must also have ID < 50

等等。

编辑:

好的,所以你的初始查询是:

List<Permission> clearence = student.PermissionLevels.Where(u => u.Id == Id &&( u.Add == permissionNeeded || u.Permission.Name == PermissionTypes.Owner)).ToList();

但请注意,这会创建一个列表,因此对其进行的任何进一步工作都将是Linq-to-objects的问题。我们将在一分钟内回到这一点,因为它有时是好的,有时不是。

现在,如果我理解正确,您需要针对不同情况使用不同的集合,您可以按照以下方式对查询进行处理:

var set0 = clearance.Where(u.Add = true || u.Owner == true);
var set1 = clearance.Where(u.Edit = true || u.Owner == true);
var set2 = clearance.Where(u.Delete= true || u.Owner == true);
var set3 = clearance.Where(u.View= true || u.Owner == true);

现在,这个工作,但可能不是最好的方法。如果我们回到原始查询,我们不必执行ToList(),但可以:

IQueryable<Permission> clearence = student.PermissionLevels.Where(u => u.Id == Id &&( u.Add == permissionNeeded || u.Permission.Name == PermissionTypes.Owner));

现在,在第一种情况下,因为我们构建了一个列表,我们首先获得了与支持的critera匹配的所有值,然后将其存储在内存中clearance

在第二种情况下,clearance根本不存储任何值,而是指示如何获取它们。

问题是哪个更好用。在我们最终将使用第一个查询返回的绝大多数对象的情况下,使用列表版本会有性能提升,因为它们只被加载到内存中一次,然后被占用从内存中没有再次访问数据库。

但是,在大多数情况下,最好是做第二个版本有两个原因:

  1. 我们在每种情况下都访问了数据库,但只检索了那种情况下所需的对象。
  2. 我们不会将任何内容存储在内存中超过必要的时间。超过一定数量,这本身就是一个重要的表现问题。
  3. 第一项的时间更快。
  4. 我们可以进一步完善,例如,如果我们执行以下操作:
  5. var trimmed = from set0 select new{u.Id, u.Permission.Name};

    我们检索具有Id和Name属性的匿名对象,这些对象是我们关心特定情况的所有内容,并不是从数据库或其他来源检索所有相关字段。

答案 3 :(得分:0)

我最近更喜欢使用Dictionary而不是switch语句。您可以将所有lambas存储在Dictionary<PermissionNeeded, Func<User, bool>>中,如下所示:

Dictionary<PermissionNeeded, Func<User, bool>> Permissions = 
    new Dictionary<PermissionNeeded, Func<User, bool>> {
        { PermissionNeeded.Add, u => u.Add }, // don't need to specify == true
        { PermissionNeeded.Edit, u => u.Edit }, 
        ... 
        etc
    };

你会这样称呼它:

var clearance = Permissions[PermissionNeeded.Add](user);

或者

var clearance = Permissions[PermissionNeeded.Add](user) && Permissions[PermissionNeeded.Edit](user);

或者

var clearance = Permission[PermissionNeeded.Add](user) || Permissions[PermissionNeeded.View](user);

等等。即使你没有用户对象,我认为这仍然是有效的,并使代码非常容易阅读,如果你必须修改你的功能,它在字典中全部......