PredicateBuilder和嵌套谓词

时间:2009-11-19 17:30:36

标签: linq-to-sql predicatebuilder

我正在尝试使用Albahari中的谓词创建一个TSQL语句,如:

select * from channel
where channel.VendorID IN (@vendorIDs)
AND channel.FranchiseID IN (@franchiseIDs)

或类似谓词:c => (c.VendorID = x || c.VendorID == x2 ...)&& (c.FranchiseID == f || c.FranchiseID == f2 ...)

但是我遇到了麻烦。这是我的尝试:

    var vendorPredicate = PredicateBuilder.False<Channel>();
    foreach (Vendor vendor in workOrderSessionData.SelectedVendors)
    {
        int tempId = vendor.VendorID;
        vendorPredicate = vendorPredicate.Or(c => c.VendorID == tempId);
    }

    var franchisePredicate = PredicateBuilder.False<Channel>();
    foreach (Franchise franchise in workOrderSessionData.SelectedFranchises)
    {
        int tempId = franchise.FranchiseID;
        franchisePredicate = franchisePredicate.Or(c => c.FranchiseID == tempId);
        // doesn't work franchisePredicate.Or(vendorPredicate);
    }

Channel.SelectByPredicate(franchisePredicate);

我的表有60,000行,所以进入数据库并选择所有行,然后过滤不是一个选项。 Channel是LinqToSql实体。 SelectedFranchises或SelectedVendors也可以为空,但不能同时为空。 编辑:我需要通过channel.Franchise.Name来区分这个列表..也许我应该只使用存储过程?

你会怎么做?

3 个答案:

答案 0 :(得分:2)

为了不使用“Contains()”语句,为了解决整个谓词问题?

IE

var myResults =
    from c in Channel
    where
        workOrderSessionData.SelectedVendors.Select(sv => 
            sv.VendorID).Contains(c.VendorID)

        && workOrderSessionData.SelectedFranchises.Select(sf => 
            sf.FranchiseID).Contains(c.FranchiseID)
    select c;
Channel.SelectByPredicate(franchisePredicate);

或者,要使用谓词方法,您不希望将它们与“或”连接,因为在示例SQL语句中这两个条件是“和”。相反,只需通过where子句连续运行它们。我不知道你的SelectByPredicate函数是如何工作的,但你可能会成功地遵循相同的模式:

var myResults = Channel.SelectByPredicate(franchisePredicate);
myResults = myResults.SelectByPredicate(vendorPredicate);

var myResults = Channel.Where(franchisePredicate).Where(vendorPredicate);

从评论中的讨论更新

如果workordersessiondata至少包含其中一个id,那么你想要的只是匹配供应商ID /特许经营ID,你将使用以下逻辑:

List<int> VendorIDs = workOrderSessionData.SelectedVendors.Select(sv => 
    sv.VendorID).ToList();

List<int> FranchiseIDs = workOrderSessionData.SelectedFranchises.Select(sf => 
    sf.FranchiseID).ToList();

var myResults = Channel;

if(VendorIDs.Count > 0)
    myResults = MyResults.Where(c => VendorIDs.Contains(c.VendorID));

if(FranchiseIDs.Count > 0)
    myResults = MyResults.Where(c => FranchiseIDs.Contains(c.FranchiseID));

答案 1 :(得分:0)

我刚刚做了这个:

var prope = outerWhere.ToString();
if (prope.Equals("f => True") == false || prope.Equals("f => False") == false)
  query = query.Where(outerWhere);

也许是所有版本中最干净的......

答案 2 :(得分:0)

鉴于扩展名:

public static class PredicateExtensions
{
    public static Predicate<T> Or<T>(this Predicate<T> @this, Predicate<T> or) {
        return value => @this(value) || or(value);
    }

    public static Predicate<T> And<T>(this Predicate<T> @this, Predicate<T> and) {
        return value => @this(value) && and(value);
    }
}

你可以这样做:

    Predicate<Channel> vendorPredicate = c => false;

    foreach (var vendor in workOrderSessionData.SelectedVendors)
    {
        int tempId = vendor.VendorID;       
        vendorPredicate = vendorPredicate.Or(c => c.VendorID == tempId);
    }

    Predicate<Channel> franchisePredicate = c => false;
    foreach (var franchise in workOrderSessionData.SelectedFranchises)
    {
        int tempid = franchise.FranchiseID;
        franchisePredicate = franchisePredicate.Or(c => c.FranchiseID == tempid);
    }

    var channelPredicate = vendorPredicate.And(franchisePredicate);

    var query = Channels.Where (c => channelPredicate(c));
}