我正在使用svcutil生成的OrganizationServiceContext实现来从CRM中检索实体:
context.new_productSet.First(p => p.new_name == "Product 1");
是否可以一次检索具有不同属性值的多个实体 - (像SQL中的IN运算符一样)?
示例:我想通过一次调用检索多个产品(“产品1”,“产品2”,...)。产品名称列表是动态的,存储在名为productNames的数组中。
答案 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);
请参阅下文以获取进一步说明。
答案 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样式。