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

fil*_*lip 2 dynamics-crm dynamics-crm-2011

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

context.new_productSet.First(p => p.new_name == "Product 1");
Run Code Online (Sandbox Code Playgroud)

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

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

Ale*_*lex 7

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

Product.Where(e => e.Name == desiredName)
Run Code Online (Sandbox Code Playgroud)

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

如果你无法避免这种类型的查询,你必须.ToList()首先获得数据(这可能导致一个巨大的结果集,并且可能会变得非常慢):

Product.ToList().Where(e => e.Name == desiredName)
Run Code Online (Sandbox Code Playgroud)

这将有效,因为现在.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"));
Run Code Online (Sandbox Code Playgroud)

或者使用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;
Run Code Online (Sandbox Code Playgroud)


Kje*_*sen 6

如果结合 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有了这个方法,您现在就可以根据您的上下文使用它了。首先记住导入扩展的命名空间以使该方法在 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();
     }
}
Run Code Online (Sandbox Code Playgroud)

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

正如您所看到的,whereIn 子句添加了 lambda 样式表达式,其中查询的其余部分使用 Linq 样式。