2015-07-21 34 views
0

我正在寻找一些有关特定Linq连接查询的帮助。我的Linq知识是相当基础的,我一直在努力拼写正确的连接代码。Linq加入以针对Dynamics CRM 2015执行特定查询

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

显然,CRM Linq Provider(ref1,ref2ref3等)存在局限性。当使用我熟悉的那种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如何正常完成这项工作。所有帮助非常感谢。

SQL查询我想建立使用LINQ:

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提供程序的限制)。该列表必须是而不是,与RelatedEntity通过CollectionOne相关,但是RelatedEntity通过CollectionTwo相关。我希望这很清楚。

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; } 
} 
+0

您可以添加类建模吗? – Andre

+0

正如我所说,我的真实生活挑战与自动生成的巨大的CRM类模型有关。你在问这些问题,还是仅仅是一些类可以用我简单的SQL例子呢? – getsetcode

+0

只是示例中的类 – Andre

回答

1

问题就出在你的要求:

我想回到的地方是与给定ID相关联 主要实体的所有实例在一个N:N的关系,并没有关联 在另一个N:N关系中具有相同的ID。

您无法使用Dynamics CRM中的Linq查询完成此操作。 Dynamics CRM的Linq查询转换为QueryExpression查询。使用QueryExpression不可能选择与其他记录关联的记录而不是

同样重要的是:左外部连接不受LINQ for CRM支持,但受QueryExpression查询支持。

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

+0

谢谢,至少这意味着我必须完全改变我的方法,而不是让我的头撞在这堵砖墙上。感谢您的建议。 – getsetcode

+0

我很同情你。忘了提及LINQ for CRM不支持左外连接。这是将他们推到一边并使用QueryExpression查询的强烈动机。我将这添加到我的答案中。 –

+0

再次感谢。 QueryExpression的问题是我需要硬编码所有的实体和属性名称。使用CrmSvcUtil.exe实用程序生成的强类型实体更加优雅。无论如何,我正在研究一种不需要左连接的新方法。祝我好运:) – getsetcode

1

一句警告:下面的工作对我来说,当我不得不面对类似的要求,但它可能是一个性能命中该系统根据数据,其他自定义,等彻底的测试是必须的

你可以用插件“欺骗”你的方式。

  1. 整数字段添加到MainEntity为每个需要跟踪的
  2. 建设,其对相关记录并更新MainEntity新增领域(这应该被注册为同步后的一个插件关系在Retrieve/RetrieveMultiple消息上操作)。通过不安全的配置将其字段和关系名称提供给可重用目的。

现在,您可以查询MainEntity,知道你所需要的一切,没有更多的明确连接需要(你也可以拥有列表作为视图如果您需要/想它)。

+1

感谢您的建议。然而基于@ henk-van-boeijen的建议,我决定研究一种新的数据模型,而不是希望这意味着我不需要'欺骗'! – getsetcode

+0

如果数据不是一成不变的,那么将其重组为最佳行动方案 – Alex