【问题标题】:LINQ to Dynamics CRM Query filtering records locallyLINQ to Dynamics CRM 查询本地过滤记录
【发布时间】:2011-06-24 01:03:41
【问题描述】:

我使用 CRM 2011 RC (v5) LINQ-to-CRM 提供程序编写了一个 Linq to CRM 查询。我有一个本地声明的 List 我想加入一个 CRM 实体,我希望在 CRM 服务器上执行查询。一个例子可能会有所帮助:

MyObject myObject = new MyObject();
List<myAccount> myAccountsList = new List<myAccount>();

myAccountsList.Add(new myAccount() {AccountNumber = "123"};
myAccountsList.Add(new myAccount() {AccountNumber = "456"};

myObject.ListOfAccounts = myAccountsList;

var accountsQuery = from ax in myObject.ListOfAccounts
                    join a in orgContext.CreateQuery<customAccountEntity>() on ax.AccountNumber equals a.account_number
                    select a;

foreach(var item in accountsQuery)
{
    Console.WriteLine("Id of record retrieved: " + a.Id.ToString());
}

上面的代码编译并执行,但是,在检索到整个 CRM 实体记录集后,记录的过滤是在本地执行的。显然,当 CRM 实体包含数千行时,查询将执行不佳甚至超时。

我已阅读有关 IQueryable 和 IEnumerable 的信息,并尝试使用 AsQueryable() 扩展方法转换列表,但没有效果。我需要我上面的 Linq 查询来运行这样的 SQL:

SELECT a.*
FROM customAccountEntity AS a
WHERE a.account_number IN ('123', '456');

如果想连接多个字段,也可以使用临时表。我怎样才能做到这一点?

【问题讨论】:

    标签: c# linq dynamics-crm dynamics-crm-2011


    【解决方案1】:

    经过大量的头撞和研究后,我使用Predicate BuilderLINQKit 解决了这个问题。我需要使用本地 List 中的 keys 创建一个基于 Or 的谓词,然后将谓词传递给 Where LINQ 扩展方法。重要的是,我需要调用 LINQKit 公开的 AsExpandable 扩展方法。所以我的代码看起来像这样:

    var predicate = PredicateBuilder.False<customAccountEntity>();
    // Loop through the local List creating an Or based predicate
    foreach (var item in myAccountsList)
    {
        string temp = item.AccountNumber;
        predicate = predicate.Or (x => x.customCrmEntityAttribute == temp);
    }
    // The variable predicate is of type Expression<Func<customAccountEntity, bool>>
    var myLinqToCrmQuery =  from ax in myObject.ListOfAccounts
                            from cx in orgContext.CreateQuery<customAccountEntity>().AsExpandable().Where(predicate)
                            where ax.AccountNumber == cx.account_number
                            select cx;
    
    foreach (resultItem in myLinqToCrmQuery)
    {
        Console.WriteLine("Account Id: " + resultItem.Id);
    }
    

    以上代码将在 CRM 服务器上运行一条 SQL 语句,如下所示:

    SELECT a.*
    FROM customAccountEntity AS a
    WHERE a.account_number = '123' OR a.account_number = '456'
    

    这意味着我可以在运行时创建一个动态 where 子句,并且知道我的查询将在 CRM SQL Server 上运行过滤逻辑。希望这对其他人有帮助。

    【讨论】:

      【解决方案2】:

      您也可以简单地使用连接表达式进行过滤,而不是使用谓词。

      var myLinqToCrmQuery =  from ax in myObject.ListOfAccounts
                                  join cx in orgContext.CreateQuery<customAccountEntity> on ax.AccountNumber equals cx.account_number                      
                                  select cx;
      

      干杯, 卢卡斯

      【讨论】:

      • 我希望查询在服务器上运行。使用连接表达式,过滤在客户端本地完成。
      【解决方案3】:

      编辑:试试那个:

      MyObject myObject = new MyObject();
      List<myAccount> myAccountsList = new List<myAccount>();
      
      myAccountsList.Add(new myAccount() {AccountNumber = "123"};
      myAccountsList.Add(new myAccount() {AccountNumber = "456"};
      
      myObject.ListOfAccounts = myAccountsList;
      
      var accountNumbers = myObject.ListOfAccounts.Select(a => a.AccountNumber);
      
      var accountsQuery = orgContext.CreateQuery<customAccountEntity>()
                                    .Where(a => accountNumbers.Contains(a.account_number));
      
      foreach(var item in accountsQuery)
      {
          Console.WriteLine("Id of record retrieved: " + a.Id.ToString());
      }
      

      编辑:如果您的查询提供者不支持包含,请使用多个 OR 构建 Where 条件,您可以使用 predicate builder 来简化此操作

      【讨论】:

      • 我已经在使用 Linq-to-Crm 查询提供程序 - 我可以在同一个查询中使用多个提供程序吗?
      • 好的,在仔细查看您的查询之后,我认为您应该反过来(没有加入,但包含)
      • 我希望将我的查询转换为 SQL,并在 SQL Server 上运行过滤。 Contains 扩展方法只是在本地进行过滤。
      • Contains 可以翻译为 SQL 中的 IN 语句,并且您使用本地对象 (ListOfAccounts),恕我直言,这是最好的方法
      • LinqPad 示例:var ids = new []{ 1, 2, 3}; var query = Users.Where(u => ids.Contains(u.Id));转换为:SELECT [t0].[Id], [t0].[Email], [t0].[Password] FROM [User] AS [t0] WHERE [t0].[Id] IN (@p0, @p1 , @p2)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多