1

我试图理解为什么这两个语句的 sql 是不同的(区别似乎在于确定是在 select 中添加 SignedXml 还是使用 case 语句。但是为什么?)。

myTable.Where(p => p.OwnerID.Equals(owner) && p.FolderID == folderId)
       .Select(source => new SignedNativeAnalysis
       {
          ID = source.ID,
          Name = source.Name,
          Created = source.Created,
          FolderID = source.FolderID,
          Locked = source.Locked,
          Modified = source.Modified,
          OwnerID = source.OwnerID,
          IsSigned = source.SignedXml != null
       });

这会产生类似的东西:

exec sp_executesql N'SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[Name] AS [Name], 
[Extent1].[Created] AS [Created], 
[Extent1].[FolderID] AS [FolderID], 
[Extent1].[Locked] AS [Locked], 
[Extent1].[Modified] AS [Modified], 
[Extent1].[OwnerID] AS [OwnerID], 
CASE WHEN ([Extent1].[SignedXml] IS NOT NULL) THEN cast(1 as bit) WHEN ([Extent1].[SignedXml] IS NULL) THEN cast(0 as bit) END AS [C1]
FROM [dbo].[NativeAnalyses] AS [Extent1]
WHERE ([Extent1].[OwnerID] = @p__linq__0) AND ([Extent1].[FolderID] = @p__linq__1)',N'@p__linq__0 uniqueidentifier,@p__linq__1 

vs 当我使用函数进行选择时:

myTable.Where(p => p.OwnerID.Equals(owner) && p.FolderID == folderId)
       .Select(Select);

和选择是

private SignedNativeAnalysis Select(NativeAnalysis source)
{
      return new SignedNativeAnalysis
      {
        ID = source.ID,
        Name = source.Name,
        Created = source.Created,
        FolderID = source.FolderID,
        Locked = source.Locked,
        Modified = source.Modified,
        OwnerID = source.OwnerID,
        IsSigned = source.SignedXml != null
      };
}

这会产生类似的东西:

exec sp_executesql N'SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[Name] AS [Name], 
[Extent1].[ModelXml] AS [ModelXml], 
[Extent1].[Created] AS [Created], 
[Extent1].[Modified] AS [Modified], 
[Extent1].[OwnerID] AS [OwnerID], 
[Extent1].[SignedXml] AS [SignedXml], 
[Extent1].[FolderID] AS [FolderID], 
[Extent1].[Locked] AS [Locked]
FROM [dbo].[NativeAnalyses] AS [Extent1]
WHERE ([Extent1].[OwnerID] = @p__linq__0) AND ([Extent1].[FolderID] = @p__linq__1)',N'@p__linq__0 uniqueidentifier,@p__linq__1 

而 SignedNativeAnalysis 只是继承了带有一个额外属性的 NativeAnalysis。

internal class SignedNativeAnalysis : NativeAnalysis
{
   public bool IsSigned { get; set; }
}

更新:根据建议,我尝试使用表达式来实现我想要的结果,但我得到了一个异常:

Expression<Func<NativeAnalysis, SignedNativeAnalysis>> signed = p => Select(p);
myTable.Where(p => p.OwnerID.Equals(owner) && p.FolderID == folderId)
       .Select(signed)

LINQ to Entities 无法识别方法“SignedNativeAnalysis Select(OverseerUI.EntityFramework.NativeAnalysis)”方法,并且该方法无法转换为存储表达式。

4

1 回答 1

2

有个窍门。实体框架选择不采用 Func<T, U>。它需要一个表达式<Func<T, U>>。

因此,当您传递 lambda 时,编译器会将您的 lambda 转换为表达式,将其传递给 EF,EF 将表达式转换为 SQL 代码。

当您传递 Func<T, U> 时,无法将其转换为表达式。Enumerable.Select 扩展方法——它采用一个普通的 Func,而不是一个表达式——来代替。所以 EF 在 SQL 中执行第一部分,直到 Where。然后将结果传递给在内存中执行投影的 Linq to Object。

你仍然可以做动态的事情,但是你必须创建一个 Expression 的实例,而不是一个委托。

于 2013-06-19T21:59:20.190 回答