如何在实体框架中的子字符串和整数上生成连接?

时间:2013-06-03 14:44:54

标签: sql linq entity-framework

使用Entity Framework,我正在尝试加入两个这样的表。

...
join f in ent.FTypes on Int32.Parse(c.CourseID[0].ToString()) equals f.FTypeID
...

字符串CourseID的第一个字符是数字,FTypeID是int。

这似乎不起作用。我收到的异常消息是:

LINQ to Entities无法识别方法'Int32 Parse(System.String)'方法,并且此方法无法转换为存储表达式。“} System.Exception {System.NotSupportedException}

我想要复制的是等效的SQL字符串(工作正常):

join FType f on SUBSTRING(c.CourseID, 1, 1) = f.FTypeID

有没有人有解决方案必须在LINQ to Entities中执行此操作?

2 个答案:

答案 0 :(得分:3)

这是一个相当令人讨厌的联接,但我在实体框架中做了一些类似数据的测试,并得出了你可以测试的东西。

它使用string.Substring从字符串操作数中获取第一个字符,然后使用仅EF方法SqlFunctions.StringConvert的组合(这些方法可在System.Data.Objects.SqlClient中找到)对于整数操作数,使用强制转换为double 1 ,最后为string.Trim 2

我已对此进行了测试并确认至少在EF 4中支持所有函数。问题中提出或推荐的其他几种方法都不起作用,因为Entity Framework不知道如何将它们转换为适当的SQL等效。

join f in ent.FTypes
on c.CourseID.Substring(0, 1) 
   equals SqlFunctions.StringConvert((double)f.FTypeID).Trim()

它生成一个如下所示的SQL连接:

INNER JOIN [dbo].[FTypes] AS [Extent2] 
ON ((SUBSTRING([Extent1].[CourseID], 0 + 1, 1)) = (LTRIM(RTRIM(STR( CAST( [Extent2].[FTypeID] AS float)))))) 
OR ((SUBSTRING([Extent1].[CourseID], 0 + 1, 1) IS NULL) AND (LTRIM(RTRIM(STR( CAST( [Extent2].[FTypeID] AS float)))) IS NULL))

因此,基于此,您可能需要根据需要进行一些额外的过滤。

试一试,看看是否有助于解决问题。


1 强制转换为double是必要的,因为SqlFunctions.StringConvert没有整数的重载,并且没有其他单个最佳匹配,所以我强制一个。

2 需要修剪结果字符串,因为字符串转换会产生一些多余的填充。

答案 1 :(得分:0)

我不确定这在 8 年前是否有效,但是现代 EF6 实现允许您添加匿名类型,因此您可以将转换添加到初始选择语句中,然后您就可以进行比较直接在连接中添加新属性。

    from c in ent.Courses
    select new { typeId = c.CourseId.Substring(0, 1), c }
    join f in ent.FTypes.Select(t => new { stringId = 
    t.FTypeId.ToString(), t }
    on c.typeId equals f.stringId into ...
<块引用>

注意: join 语句似乎不支持 ToString() 但 select 语句支持。

您也可以将 CouresId.Substring 移动到 join 语句中,但在那里运行效率可能较低。

SQL 结果如下:

INNER JOIN [ent].[FTypes] AS [Extent2] ON 
(LTRIM(RTRIM(SUBSTRING([Extent1].[nvarchar(max)], 3 + 1, 1)))) =  
CAST([Extent2].[Id] AS nvarchar(max))