Linq到Sql Concat问题

时间:2012-05-23 02:42:46

标签: linq entity-framework linq-to-sql concat

所以我有这个功能:

public static BaseList GetVersesByChapterVerseRanges(字符串翻译,BaseList criteriaList)     {         BaseList returnValue = new BaseList();;

    if(criteriaList.Count() > 0)
    {

        List<VerseMaster.BusinessLayer.Vers> queryList = new List<Vers>();

        int bookId = criteriaList[0].Book.BookId;
        int StartChapter = criteriaList[0].StartChapter;
        int EndChapter = criteriaList[0].EndChapter;
        int StartVerse = criteriaList[0].StartChapterStartVerse;
        int EndVerse = criteriaList[0].EndChapterEndVerse;
        var searchQuery = (from v in VerseMaster.BusinessLayer.Controller.Controller.VerseMasterEntities.Verses where v.Translation.ToLower().StartsWith(translation.ToLower()) && v.BookId == bookId && v.ChapterNumber >= StartChapter && v.ChapterNumber <= EndChapter && (v.ChapterNumber == StartChapter ? (v.VerseNumber >= StartVerse) : true) && (v.ChapterNumber == EndChapter ? (v.VerseNumber <= EndVerse) : true) orderby v.ChapterNumber, v.VerseNumber ascending select v);


        for(int i = 1; i < criteriaList.Count(); i++)
        {
            bookId = criteriaList[i].Book.BookId;
            StartChapter = criteriaList[i].StartChapter;
            EndChapter = criteriaList[i].EndChapter;
            StartVerse = criteriaList[i].StartChapterStartVerse;
            EndVerse = criteriaList[i].EndChapterEndVerse;
            VerseMaster.BusinessLayer.DataObjects.Helper.VerseSearchCriteria criteria = criteriaList[i];
            searchQuery = (System.Linq.IOrderedQueryable<VerseMaster.BusinessLayer.Vers>)searchQuery.Concat(from v in VerseMaster.BusinessLayer.Controller.Controller.VerseMasterEntities.Verses where v.Translation.ToLower().StartsWith(translation.ToLower()) && v.BookId == bookId && v.ChapterNumber >= StartChapter && v.ChapterNumber <= EndChapter && (v.ChapterNumber == StartChapter ? (v.VerseNumber >= StartVerse) : true) && (v.ChapterNumber == EndChapter ? (v.VerseNumber <= EndVerse) : true) orderby v.ChapterNumber, v.VerseNumber ascending select v);

        }

        string traceString = ((System.Data.Objects.ObjectQuery)searchQuery).ToTraceString();

        foreach (var entVerse in searchQuery)
        {
            VerseMaster.BusinessLayer.DataObjects.IVerse verse = new VerseMaster.BusinessLayer.DataObjects.Verse();
            LoadVerseFromEntityVerse(ref verse, entVerse);

            Console.Write(String.Format("Chapter={0} Verse={1} Text={2}\n", entVerse.ChapterNumber, entVerse.VerseNumber, entVerse.Verse));
            //returnValue.Add((VerseMaster.BusinessLayer.DataObjects.Verse)verse);
        }
    }

    return returnValue;
}

因此,出于某种原因,我必须将进入linq查询的每个参数转换为标准整数,因为它有错误,不确定它是否相关。所以生成的sql是:

 SELECT 
[UnionAll2].[C1] AS [C1], 
[UnionAll2].[C2] AS [C2], 
[UnionAll2].[C3] AS [C3], 
[UnionAll2].[C4] AS [C4], 
[UnionAll2].[C5] AS [C5], 
[UnionAll2].[C6] AS [C6]
FROM  (SELECT 
    [UnionAll1].[VerseId] AS [C1], 
    [UnionAll1].[ChapterNumber] AS [C2], 
    [UnionAll1].[VerseNumber] AS [C3], 
    [UnionAll1].[Verse] AS [C4], 
    [UnionAll1].[Translation] AS [C5], 
    [UnionAll1].[BookId] AS [C6]
    FROM  (SELECT 
        [Extent1].[VerseId] AS [VerseId], 
        [Extent1].[ChapterNumber] AS [ChapterNumber], 
        [Extent1].[VerseNumber] AS [VerseNumber], 
        [Extent1].[Verse] AS [Verse], 
        [Extent1].[Translation] AS [Translation], 
        [Extent1].[BookId] AS [BookId]
        FROM [dbo].[Verses] AS [Extent1]
        WHERE (( CAST(CHARINDEX(LOWER(@p__linq__0), LOWER([Extent1].[Translation])) AS int)) = 1) AND ([Extent1].[BookId] = @p__linq__1) AND ([Extent1].[ChapterNumber] >= @p__linq__2) AND ([Extent1].[ChapterNumber] <= @p__linq__3) AND ((CASE WHEN ([Extent1].[ChapterNumber] = @p__linq__4) THEN CASE WHEN ([Extent1].[VerseNumber] >= @p__linq__5) THEN cast(1 as bit) WHEN ( NOT ([Extent1].[VerseNumber] >= @p__linq__5)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1) AND ((CASE WHEN ([Extent1].[ChapterNumber] = @p__linq__6) THEN CASE WHEN ([Extent1].[VerseNumber] <= @p__linq__7) THEN cast(1 as bit) WHEN ( NOT ([Extent1].[VerseNumber] <= @p__linq__7)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1)
    UNION ALL
        SELECT 
        [Extent2].[VerseId] AS [VerseId], 
        [Extent2].[ChapterNumber] AS [ChapterNumber], 
        [Extent2].[VerseNumber] AS [VerseNumber], 
        [Extent2].[Verse] AS [Verse], 
        [Extent2].[Translation] AS [Translation], 
        [Extent2].[BookId] AS [BookId]
        FROM [dbo].[Verses] AS [Extent2]
        WHERE (( CAST(CHARINDEX(LOWER(@p__linq__8), LOWER([Extent2].[Translation])) AS int)) = 1) AND ([Extent2].[BookId] = @p__linq__9) AND ([Extent2].[ChapterNumber] >= @p__linq__10) AND ([Extent2].[ChapterNumber] <= @p__linq__11) AND ((CASE WHEN ([Extent2].[ChapterNumber] = @p__linq__12) THEN CASE WHEN ([Extent2].[VerseNumber] >= @p__linq__13) THEN cast(1 as bit) WHEN ( NOT ([Extent2].[VerseNumber] >= @p__linq__13)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1) AND ((CASE WHEN ([Extent2].[ChapterNumber] = @p__linq__14) THEN CASE WHEN ([Extent2].[VerseNumber] <= @p__linq__15) THEN cast(1 as bit) WHEN ( NOT ([Extent2].[VerseNumber] <= @p__linq__15)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1)) AS [UnionAll1]
UNION ALL
    SELECT 
    [Extent3].[VerseId] AS [VerseId], 
    [Extent3].[ChapterNumber] AS [ChapterNumber], 
    [Extent3].[VerseNumber] AS [VerseNumber], 
    [Extent3].[Verse] AS [Verse], 
    [Extent3].[Translation] AS [Translation], 
    [Extent3].[BookId] AS [BookId]
    FROM [dbo].[Verses] AS [Extent3]
    WHERE (( CAST(CHARINDEX(LOWER(@p__linq__16), LOWER([Extent3].[Translation])) AS int)) = 1) AND ([Extent3].[BookId] = @p__linq__17) AND ([Extent3].[ChapterNumber] >= @p__linq__18) AND ([Extent3].[ChapterNumber] <= @p__linq__19) AND ((CASE WHEN ([Extent3].[ChapterNumber] = @p__linq__20) THEN CASE WHEN ([Extent3].[VerseNumber] >= @p__linq__21) THEN cast(1 as bit) WHEN ( NOT ([Extent3].[VerseNumber] >= @p__linq__21)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1) AND ((CASE WHEN ([Extent3].[ChapterNumber] = @p__linq__22) THEN CASE WHEN ([Extent3].[VerseNumber] <= @p__linq__23) THEN cast(1 as bit) WHEN ( NOT ([Extent3].[VerseNumber] <= @p__linq__23)) THEN cast(0 as bit) END ELSE cast(1 as bit) END) = 1)) AS [UnionAll2]

所以问题在于,由于某些原因,它处理我给它的每个参数,好像我发送了3组相同的参数并连接,因此它返回相同的3节经文。我不知道为什么它这样做因为我不是linq的专家或实体框架,有什么建议吗?

1 个答案:

答案 0 :(得分:2)

这是modified closure问题的一个非常棘手的例子。在for循环中,您将生成一个使用变量bookId等的查询部分。在执行查询时,它会使用这些变量在此时具有的值 ,这是循环最后一次迭代后的值。 (棘手的部分是通常捕获循环变量,但这里是关于在循环范围之外声明的变量)。

如果在for循环中声明变量会有所不同,因为每个查询部分都会捕获它自己的变量实例(称为闭包)。

好消息:你可以这样做,同时清理你的代码!

if(criteriaList.Count() > 0)
{
    IQueryable<Verse> baseQuery = null;
    for(int i = 0; i < criteriaList.Count(); i++) // starting i = 0 now !
    {
        int bookId = criteriaList[0].Book.BookId;
        int StartChapter = criteriaList[0].StartChapter;
        int EndChapter = criteriaList[0].EndChapter;
        int StartVerse = criteriaList[0].StartChapterStartVerse;
        int EndVerse = criteriaList[0].EndChapterEndVerse;
        searchQuery = (IOrderedQueryable<Vers>)searchQuery.Concat(
            from v in Controller.Controller.VerseMasterEntities.Verses 
            where v.Translation.ToLower().StartsWith(translation.ToLower()) 
                && v.BookId == bookId 
                && v.ChapterNumber >= StartChapter 
                && v.ChapterNumber <= EndChapter 
                && (v.ChapterNumber == StartChapter ? (v.VerseNumber >= StartVerse) : true) 
                && (v.ChapterNumber == EndChapter ? (v.VerseNumber <= EndVerse) : true) 
            select v);

        if (i == 0)
            baseQuery = searchQuery;
        else
            baseQuery = baseQuery.Concat(searchQuery);
    }
    ...

(稍后再做订购)