2013-06-28 87 views
3

我对SQLite数据库有Entity Framework 4模型。部分模型看起来像这样 enter image description hereLINQ to Entities物化错误

所有Id字段的类型都是Guid(SQLite表DDL中的uniqueidentifier)。但是当我运行下面的LINQ查询时,我得到异常。

var query = AbonentPfrs.Select(a => 
    new 
    { 
     AbPfr = a, 
     Pfr = a.PfrCertificates.Select(c => c.Id), 
     Ac = a.AcCertificates.Select(c => c.Id) 
    } 
); 
query.ToList(); 

当我运行它,我得到

System.InvalidOperationException: The type of the key field 'Id' is expected to be 'System.Guid', but the value provided is actually of type 'System.String'. 

更新:我发现EF生成SQL查询,真正返回一个字符串作为实体的一个标识符。

行进至DB ((query as ObjectQuery).ToTraceString())的SQL是这样的:

SELECT 
[UnionAll1].[C2] AS [C1], 
[UnionAll1].[C3] AS [C2], 
[UnionAll1].[Id] AS [C3], 
[UnionAll1].[PfrRegNumber] AS [C4], 
[UnionAll1].[PfrUnitId] AS [C5], 
[UnionAll1].[Account_Id] AS [C6], 
[UnionAll1].[ActiveCertificate_Id] AS [C7], 
[UnionAll1].[C1] AS [C8], 
[UnionAll1].[Id1] AS [C9], 
[UnionAll1].[C4] AS [C10] 
FROM (SELECT 
    CASE WHEN ([Extent2].[Id] IS NULL) THEN NULL ELSE 1 END AS [C1], 
    1 AS [C2], 
    1 AS [C3], 
    [Extent1].[Id] AS [Id], 
    [Extent1].[PfrRegNumber] AS [PfrRegNumber], 
    [Extent1].[PfrUnitId] AS [PfrUnitId], 
    [Extent1].[Account_Id] AS [Account_Id], 
    [Extent1].[ActiveCertificate_Id] AS [ActiveCertificate_Id], 
    [Extent2].[Id] AS [Id1], 
    NULL AS [C4] 
    FROM [AbonentPfrs] AS [Extent1] 
    LEFT OUTER JOIN [Certificates] AS [Extent2] ON [Extent1].[Id] = [Extent2].[AbonentPfr_PfrCertificates_Certificate_Id] 
UNION ALL 
    SELECT 
    2 AS [C1], 
    2 AS [C2], 
    2 AS [C3], 
    [Extent3].[Id] AS [Id], 
    [Extent3].[PfrRegNumber] AS [PfrRegNumber], 
    [Extent3].[PfrUnitId] AS [PfrUnitId], 
    [Extent3].[Account_Id] AS [Account_Id], 
    [Extent3].[ActiveCertificate_Id] AS [ActiveCertificate_Id], 
    NULL AS [C4], 
    [Extent4].[Id] AS [Id1] 
    FROM [AbonentPfrs] AS [Extent3] 
    INNER JOIN [Certificates] AS [Extent4] ON [Extent3].[Id] = [Extent4].[AbonentPfr_AcCertificates_Certificate_Id]) AS [UnionAll1] 
ORDER BY [UnionAll1].[Id] ASC, [UnionAll1].[C1] ASC 

enter image description here

的最后列的证书中的实体ID。但最后有Guid类型和之前的字符串。如果我单独运行查询的部分,然后我得到的下一列类型(FOT最后两个):

  1. 首先选择:GUID,对象
  2. 第二个选择:对象,的Guid
  3. UNION ALL:GUID,对象
  4. 外选择:字符串的Guid

为什么在倒数第二个栏外select返回字符串?

+0

我认为这是因为两个关系在同一个表上 - 从AbonentPfr到证书。但我不确定... – sedovav

+0

可能是因为SQLite存储GUID作为字符串? AFAIK SQLite没有本地GUID数据类型。 – okrumnow

+0

但在所有其他查询中,它的工作原理相同 – sedovav

回答

0

看来,排序是重点。没有排序,最后两列的结果类型是Guid和Objects。订购 - 字符串和Guid。这两个顺序表达式均取决于[Extent2].[Id]列。 SQLite不会操作Guid类型,所以我认为,值被转换为String。 这是EF4和System.Data.SQLite集成的难点之一。所以我需要找到一种方法来强制EF不会生成订购条款...

0

执行外部联接时,行CASE WHEN ([Extent2].[Id] IS NULL) THEN NULL ELSE 1 END AS [C1]将在您的查询遇到缺失值时返回空值C1。 在.NET中,GUID是一个值类型(128位整数),所以不能设置为null而不跳过箍环。 (有关GUID结构的更多信息,请参见Why isn't there a Guid.IsNullOrEmpty() method)。

由于返回的值是可以为空且格式为xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,因此它被假定为字符串。

+0

我已经更改了结果的图片以显示哪些类型的列。正如你可以看到问题出现在“[Extent2]。[Id]'和'NULL'的”C9“列中。但是“C10”栏很好 - 结果类型是Guid。我看不出差别。 C10是'NULL'和'[Extent4]。[Id]'的结合结果。需要说'[Extent2]。[Id]'和'[Extent4]。[Id]'具有相同的数据库类型。 – sedovav