Dynamics CRM SDK - 带有OrganizationServiceContext的linq的IN运算符

时间:2014-03-11 12:57:46

标签: dynamics-crm-2011 dynamics-crm

我正在使用svcutil生成的OrganizationServiceContext实现来从CRM中检索实体:

context.new_productSet.First(p => p.new_name == "Product 1");

是否可以一次检索具有不同属性值的多个实体 - (像SQL中的IN运算符一样)?

示例:我想通过一次调用检索多个产品(“产品1”,“产品2”,...)。产品名称列表是动态的,存储在名为productNames的数组中。

4 个答案:

答案 0 :(得分:7)

不,你不能。 CRM LINQ提供程序仅允许变量出现在表达式的左侧,而右侧必须包含常量。

Product.Where(e => e.Name == desiredName)

不支持并且不会工作(它会抱怨在比较的右侧使用变量)。

如果您无法避免此类查询,则必须首先.ToList()数据(这可能会导致巨大结果集,并且可能会变得非常缓慢):< / p>

Product.ToList().Where(e => e.Name == desiredName)

这样可行,因为现在.Where()已应用于List<>

另一种方法(我没有关于性能的数据)是创建许多查询,基本上一次获取一个记录:

// ... this is going to be a nightmare ... don't do it ...
var entities = new List<Product>();
entities.Add(Product.Where(e => e.Name == "Product 1"));
entities.Add(Product.Where(e => e.Name == "Product 2"));

或者像这样使用QueryExpression(我个人最喜欢的,因为我总是迟到)

var desiredNames = new string[]{"Product 1", "Product 2"};
var filter = new FilterExpression(LogicalOperator.And)
{
    Conditions = 
    {
        new ConditionExpression("name", ConditionOperator.In, desiredNames)
    }
};
var query = new QueryExpression(Product.EntityLogicalName)
{
    ColumnSet = new ColumnSet(true),
    Criteria = filter
};
var records = service.RetrieveMultiple(query).Entities;

答案 1 :(得分:2)

使用QueryExpression时,我们可以为where子句添加condtionexpression。 ConditionExpression采用ConditionOperator枚举器,我们可以使用ConditionOperator.In。下面是使用“In”运算符启动conidtionExpression的方法,第三个参数可以是数组或集合。

ConditionExpression ce = new ConditionExpression("EntityName",
        ConditionOperator.In, collectionObject);

请参阅下文以获取进一步说明。

http://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.query.conditionexpression.conditionexpression.aspx

答案 2 :(得分:0)

我不知道如何用Linq做到这一点,据我所知,这是不可能的。

可以使用查询表达式完成:

String[] productNames = new[] { "test1", "test2" };
QueryExpression products = new QueryExpression(Product.EntityLogicalName);
products.ColumnSet = new ColumnSet("name", "new_att1", "new_att2"); // fields to get 
products.Criteria.AddCondition("name", ConditionOperator.In,
    productNames.Cast<Object>().ToArray()); // filter by array
EntityCollection res = service.RetrieveMultiple(products);
IEnumerable<Product> opportunities = res.Entities
    .Select(product => product.ToEntity<Product>()); // you can use Linq again from here

答案 3 :(得分:0)

如果结合使用Linq和Lambda表达式是可以的,则可以完成。首先,您需要创建一个扩展方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Kipon.Dynamics.Extensions.IQueryable
{
    public static class Methods
    {
        public static IQueryable<TSource> WhereIn<TSource, TValue>(this IQueryable<TSource> source, Expression<Func<TSource, TValue>> valueSelector, IEnumerable<TValue> values)
        {
            if (null == source) { throw new ArgumentNullException("source"); }
            if (null == valueSelector) { throw new ArgumentNullException("valueSelector"); }
            if (null == values) { throw new ArgumentNullException("values"); }

            var equalExpressions = new List<BinaryExpression>();

            foreach (var value in values)
            {
                var equalsExpression = Expression.Equal(valueSelector.Body, Expression.Constant(value));
                equalExpressions.Add(equalsExpression);
            }

            ParameterExpression p = valueSelector.Parameters.Single();
            var combined = equalExpressions.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));
            var combinedLambda = Expression.Lambda<Func<TSource, bool>>(combined, p);

            return source.Where(combinedLambda);
        }
    }
}

有了此方法,您现在可以在上下文中使用它。首先,请记住导入扩展名的名称空间,以使该方法在IQueryable上可用:

using System.Linq;
using Kipon.Dynamics.Extensions.IQueryable;

public class MyClass
  {
     void myQueryMethod(CrmContext ctx, Guid[] contacts) 
     {
       var accounts = (from a in ctx.accountSet.WhereIn(ac => ac.primarycontactid.id,contacts)
                       where a.name != null
                       select a).toArray();
     }
}

据我所知,您无法挂接到Dynamics 365 Linq表达式编译器,但是以上代码将在针对CRM的一个请求中执行,并可以利用 使用Linq时不需要考虑分页等等。

如您所见,在其中的whereIn子句中添加了一个lambda样式表达式,其余查询使用的是Linq样式。