【问题标题】:Linq join to perform specific query against Dynamics CRM 2015Linq 加入对 Dynamics CRM 2015 执行特定查询
【发布时间】:2015-07-21 17:44:41
【问题描述】:

我正在寻求有关特定 Linq 连接查询的帮助。我的 Linq 知识相当基础,我整天都在努力编写正确的连接代码。

我实际上是在尝试使用由 CrmSvcUtil.exe 实用程序生成的 ServiceContext 构建一个可以与 Dynamics CRM Online 2015 SDK 一起使用的 Linq 查询。

显然,CRM Linq Provider 存在限制(ref1ref2ref3 等)。当使用我熟悉的那种 Linq 查询时,我经常会收到以下错误。似乎答案是使用更自然的 Linq 连接。

Invalid 'where' condition. An entity member is invoking an invalid property or method.

与其向您展示我的 100 多次失败尝试,我认为最好使用 SQL 示例来展示我正在尝试实现的目标。下面的示例脚本。本质上,我有一个实体,我想为其返回记录列表。这与另一个实体有两个 N:N 关系。我想返回与一个 N:N 关系中的给定 ID 相关联的主实体的所有实例,而不是与另一个 N:N 关系中的相同 ID 相关联。

我最苦恼的部分是执行一个包含内连接和左外连接的 Linq 查询。即使您没有直接使用 CRM Linq 提供程序的经验,它仍然可以帮助我了解如何在 Linq 中正常完成。非常感谢所有帮助。

我想用 Linq 构建的 SQL 查询:

DECLARE @id INT = 1

-- Should only return entities with IDs 1 and 2
SELECT a.* FROM [dbo].[MainEntity] a
INNER JOIN [dbo].[AltOne] b ON a.EntityID = b.EntityID AND b.AltOneID = @id
LEFT JOIN [dbo].[AltTwo] c ON a.EntityID = c.EntityID AND c.AltOneID = @id
WHERE c.AltOneID IS NULL

数据库设置脚本:

CREATE TABLE [dbo].[MainEntity](
    [EntityID] [int] NOT NULL,
    [EntityName] [varchar](50) NOT NULL,
    CONSTRAINT [PK_MainEntity] PRIMARY KEY CLUSTERED 
    ( 
        [EntityID] ASC 
    )
)
GO

CREATE TABLE [dbo].[AltOne](
    [EntityID] [int] NOT NULL,
    [AltOneID] [int] NOT NULL,
    CONSTRAINT [PK_AltOne] PRIMARY KEY CLUSTERED 
    (
        [EntityID] ASC,
        [AltOneID] ASC
    )
)
GO

ALTER TABLE [dbo].[AltOne]  WITH CHECK ADD  CONSTRAINT [FK_AltOne_MainEntity] FOREIGN KEY([EntityID])
REFERENCES [dbo].[MainEntity] ([EntityID])
GO

ALTER TABLE [dbo].[AltOne] CHECK CONSTRAINT [FK_AltOne_MainEntity]
GO

CREATE TABLE [dbo].[AltTwo](
    [EntityID] [int] NOT NULL,
    [AltOneID] [int] NOT NULL,
    CONSTRAINT [PK_AltTwo] PRIMARY KEY CLUSTERED 
    (
        [EntityID] ASC,
        [AltOneID] ASC
    )
)
GO

ALTER TABLE [dbo].[AltTwo]  WITH CHECK ADD  CONSTRAINT [FK_AltTwo_MainEntity] FOREIGN KEY([EntityID])
REFERENCES [dbo].[MainEntity] ([EntityID])
GO

ALTER TABLE [dbo].[AltTwo] CHECK CONSTRAINT [FK_AltTwo_MainEntity]
GO

INSERT INTO [dbo].[MainEntity] ([EntityID], [EntityName]) VALUES (1, 'Test 1')
INSERT INTO [dbo].[MainEntity] ([EntityID], [EntityName]) VALUES (2, 'Test 2')
INSERT INTO [dbo].[MainEntity] ([EntityID], [EntityName]) VALUES (3, 'Test 3')
GO

INSERT INTO [dbo].[AltOne] ([EntityID], [AltOneID]) VALUES (1, 1)
INSERT INTO [dbo].[AltOne] ([EntityID], [AltOneID]) VALUES (1, 2)
INSERT INTO [dbo].[AltOne] ([EntityID], [AltOneID]) VALUES (2, 1)
INSERT INTO [dbo].[AltOne] ([EntityID], [AltOneID]) VALUES (2, 2)
INSERT INTO [dbo].[AltOne] ([EntityID], [AltOneID]) VALUES (3, 1)
GO

INSERT INTO [dbo].[AltTwo] ([EntityID], [AltOneID]) VALUES (3, 1)
INSERT INTO [dbo].[AltTwo] ([EntityID], [AltOneID]) VALUES (1, 2)
INSERT INTO [dbo].[AltTwo] ([EntityID], [AltOneID]) VALUES (2, 2)
GO

编辑 1:

根据要求添加示例类。重申一下,我需要返回MainEntity 对象的集合而不直接使用ICollection 属性,而是使用连接(这似乎是CRM Linq 提供程序的限制)。该列表必须是通过CollectionOne与特定RelatedEntity相关,但通过CollectionTwo与同一RelatedEntity相关的对象。我希望这很清楚。

public class MainEntity
{
    public int EntityID { get; set; }
    public string EntityName { get; set; }

    public ICollection<RelationshipOne> CollectionOne { get; set; }
    public ICollection<RelationshipTwo> CollectionTwo { get; set; }
}

public class RelationshipOne
{
    public int EntityID { get; set; }
    public int AltOneID { get; set; }

    public ICollection<MainEntity> MainEntities { get; set; }
    public ICollection<RelatedEntity> RelatedEntities { get; set; }
}

public class RelationshipTwo
{
    public int EntityID { get; set; }
    public int AltOneID { get; set; }

    public ICollection<MainEntity> MainEntities { get; set; }
    public ICollection<RelatedEntity> RelatedEntities { get; set; }
}

public class RelatedEntity
{
    public int RelatedEntityID { get; set; }
    public string RelatedEntityName { get; set; }

    public ICollection<RelationshipOne> RelationshipOnes { get; set; }
    public ICollection<RelationshipTwo> RelationshipTwos { get; set; }
}

public class DummyContext
{
    public System.Data.Entity.DbSet<MainEntity> MainEntitySet { get; set; }
    public System.Data.Entity.DbSet<RelationshipOne> RelationshipOneSet { get; set; }
    public System.Data.Entity.DbSet<RelationshipTwo> RelationshipTwoSet { get; set; }
    public System.Data.Entity.DbSet<RelatedEntity> RelatedEntitySet { get; set; }
}

【问题讨论】:

  • 可以添加类建模吗?
  • 正如我所说,我的现实生活挑战与巨大的自动生成的 CRM 类模型有关。你是要那些,还是只需要一些类来配合我的简单 SQL 示例?
  • 只是示例中的类

标签: c# asp.net linq dynamics-crm-2015


【解决方案1】:

问题在于你的要求:

我想返回它所在的主实体的所有实例 与一个 N:N 关系中的给定 ID 关联,并且不关联 在另一个 N:N 关系中具有相同的 ID。

您无法通过 Dynamics CRM 中的 Linq 查询来完成此操作。 Dynamics CRM 的 Linq 查询转换为 QueryExpression 查询。使用 QueryExpression 无法选择与其他记录关联的记录。

另外需要提一下:LINQ for CRM 不支持左外连接,但QueryExpression 查询支持。

您唯一的选择是(希望)多选择一些记录,然后过滤不需要的记录。

【讨论】:

  • 谢谢,至少这意味着我必须完全改变我的方法,而不是一直用头撞这堵砖墙。感谢您的建议。
  • 我很同情你。忘了提到 LINQ for CRM 不支持左外连接。这是将它们推到一边并改用QueryExpression 查询的强烈动机。我将此添加到我的答案中。
  • 再次感谢。 QueryExpression 的问题在于我需要对所有实体和属性名称进行硬编码。使用由 CrmSvcUtil.exe 实用程序生成的强类型实体更加优雅。我正在研究一种不需要左连接的新方法。祝我好运:)
  • 是的,我使用生成的 EntityFieldnames 静态类,所以我不需要输入文字。您可以使用.ToEntity&lt;MyEntity&gt;() 方法轻松地将查询结果转换为强类型实体类。
  • 对,知道这一点很有用。谢谢。
【解决方案2】:

一句警告:当我不得不面对类似的要求时,以下方法对我有用,但根据数据、其他自定义设置等,它可能会对系统造成性能影响。彻底的测试是 必须

您可以通过插件“作弊”。

  1. 为您需要跟踪的每个关系向 MainEntity 添加一个整数字段
  2. 构建一个插件来计算相关记录并更新 MainEntity 中新添加的字段(这应该在 Retrieve/RetrieveMultiple 消息上注册为同步后操作)。出于可重用目的,通过不安全的配置为其提供字段和关系名称。

您现在可以查询MainEntity 并了解您需要的一切,不再需要显式连接(如果您需要/想要它,您也可以将列表作为视图)。

【讨论】:

  • 感谢您的建议。然而,根据@henk-van-boeijen 的建议,我决定研究一种新的数据模型,希望这意味着我不需要“作弊”!
  • 如果数据不是一成不变的,那么重组它以使其更易于使用肯定是最好的做法之一
猜你喜欢
  • 1970-01-01
  • 2015-09-24
  • 1970-01-01
  • 2011-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-28
  • 1970-01-01
相关资源
最近更新 更多