簡體   English   中英

為什么Linq-to-sql錯誤地刪除了我的聯盟中的字段?

[英]Why is Linq-to-sql incorrectly removing fields in my union?

我正在嘗試將多個查詢聚合在一起,為我的用戶提供最新的更新顯示,使用通用數據結構進行聯合支持。 在我的第一個函數中,我有以下select子句:

.Select(x => new PlayerUpdateInfo
{
    FirstName = x.PodOptimizedSearch.FirstName,
    LastName = x.PodOptimizedSearch.LastName,
    RecruitId = x.RecruitId,
    Date = x.Date,
    UpdateMessage = x.IsAddedAction
      ? "Player was added to this recruiting board by " + x.Person.FirstName
        + " " + x.Person.LastName
      : "Player was removed from this recruiting board by " + 
        x.Person.FirstName + " " + x.Person.LastName,

    // Defaults for union support
    Team = string.Empty,
    UpdateComments = x.Comments,
    TeamId = 0,
    State = string.Empty
});

調用時,這會正確生成一個返回9個字段的查詢。 第二種方法的選擇是:

select new PlayerUpdateInfo
{
    FirstName = recruit.FirstName,
    LastName = recruit.LastName,
    RecruitId = recruit.RecruitId,
    Date = asset.CreateDate,
    UpdateMessage = "New Full Game Added",

    // Defaults for union support
    Team = null,
    UpdateComments = null,
    TeamId = 0,
    State = null
    };

當此查詢本身運行時,它會正確返回9個值。 但是,當我嘗試做的時候

var query = GetFirstQuery();
query = query.union(GetSecondQuery()); 

我得到一個sql異常,查詢失敗,因為所有查詢都沒有相同數量的字段。 調查生成的SQL顯示第一個查詢是正確的,但Linq生成的第二個(聯合)查詢只有7個字段。 經過測試,似乎Linq似乎正在“優化”空值,因此它只返回一個空列而不是3,從而導致不匹配。

為什么Linq-to-sql錯誤地生成了聯合,我該如何解決這個問題呢?


編輯:

好的問題似乎是針對.Net 3.5的Linq-to-Sql中的聯合鏈接。 這顯然不會發生在4中。 使用以下代碼:

  protected IQueryable<PlayerUpdateInfo> Test1() { return PodDataContext.Assets .Select(x => new PlayerUpdateInfo { Date = DateTime.Now, FirstName = x.Title, LastName = string.Empty, RecruitId = 0, State = string.Empty, Team = string.Empty, TeamId = 0, UpdateComments = string.Empty, UpdateMessage = string.Empty }); } protected IQueryable<PlayerUpdateInfo> Test2() { return PodDataContext.SportPositions .Select(x => new PlayerUpdateInfo { Date = DateTime.Now, FirstName = string.Empty, LastName = x.Abbreviation, RecruitId = 0, State = string.Empty, Team = string.Empty, TeamId = 0, UpdateComments = string.Empty, UpdateMessage = string.Empty }); } 

然后我通過聯合鏈: var q2 = Test1().Union(Test2()).Union(Test1());

在.Net 3.5中我得到以下sql,它有一個不匹配並失敗

 SELECT [t4].[value] AS [RecruitId], [t4].[Title] AS [FirstName], [t4].[value2] AS [LastName], [t4].[value22] AS [Team], [t4].[value3] AS [Date] FROM ( SELECT [t2].[value], [t2].[Title], [t2].[value2], [t2].[value2] AS [value22], [t2].[value3] FROM ( SELECT @p0 AS [value], [t0].[Title], @p1 AS [value2], @p2 AS [value3] FROM [dbo].[Assets] AS [t0] UNION SELECT @p3 AS [value], @p4 AS [value2], [t1].[Abbreviation], @p5 AS [value3] FROM [dbo].[SportPositions] AS [t1] ) AS [t2] UNION SELECT @p6 AS [value], [t3].[Title], @p7 AS [value2], @p8 AS [value3] FROM [dbo].[Assets] AS [t3] ) AS [t4] 

在.net 4中生成以下代碼:

 SELECT [t4].[value] AS [RecruitId], [t4].[Title] AS [FirstName], [t4].[value2] AS [LastName], [t4].[value3] AS [Team], [t4].[value4] AS [TeamId], [t4].[value5] AS [State], [t4].[value6] AS [UpdateMessage], [t4].[value7] AS [UpdateComments], [t4].[value8] AS [Date] FROM ( SELECT [t2].[value], [t2].[Title], [t2].[value2], [t2].[value3], [t2].[value4], [t2].[value5], [t2].[value6], [t2].[value7], [t2].[value8] FROM ( SELECT @p0 AS [value], [t0].[Title], @p1 AS [value2], @p2 AS [value3], @p3 AS [value4], @p4 AS [value5], @p5 AS [value6], @p6 AS [value7], @p7 AS [value8] FROM [dbo].[Assets] AS [t0] UNION SELECT @p8 AS [value], @p9 AS [value2], [t1].[Abbreviation], @p10 AS [value3], @p11 AS [value4], @p12 AS [value5], @p13 AS [value6], @p14 AS [value7], @p15 AS [value8] FROM [dbo].[SportPositions] AS [t1] ) AS [t2] UNION SELECT @p16 AS [value], [t3].[Title], @p17 AS [value2], @p18 AS [value3], @p19 AS [value4], @p20 AS [value5], @p21 AS [value6], @p22 AS [value7], @p23 AS [value8] FROM [dbo].[Assets] AS [t3] ) AS [t4] 

這是有效的SQL和工作。 由於各種原因我們無法將我們的生產系統帶到.net 4,有沒有人知道我可以在.net 3.5中解決這個問題的方法?

這是一個更新的答案 - 似乎在3.5中無法關閉優化。 我在LinqPad中嘗試了很多東西,只要有一個不是從列派生的C#表達式,查詢編譯器就會將它從SQL中刪除。

所以我們需要一些從列表達式派生的東西,但我們可以強制它總是為null

這是我能夠開始工作的一個解決方案 - 編寫一個條件表達式,當列值等於它自己時返回null ; 因此總是返回null 它不會很漂亮,因為3.5中的Linq to Sql似乎在優化查詢方面非常積極(我們必須對我們想要的每個null使用唯一比較,例如在一個中使用== ,然后在下一個使用!=上); 當我們修改它以處理空值時,如果你必須在可空列上執行此操作,它會變得更加丑陋:

我只是挑選了我可以從你的代碼中看到的列名 - 但你可能想要使用不同的:

select new PlayerUpdateInfo  
{  
  FirstName = recruit.FirstName,  
  LastName = recruit.LastName,  
  RecruitId = recruit.RecruitId,  
  Date = asset.CreateDate,  
  UpdateMessage = "New Full Game Added",  

  // Defaults for union support  
  Team = recruit.FirstName = recruit.FirstName ? null : "",  
  UpdateComments = recruit.FirstName != recruit.FirstName ? "" : null,  
  TeamId = recruit.LastName = recruit.LastName ? null : "",  
  State = recruit.LastName != recruit.LastName ? "" : null
};

在LinqPad中,我在生成的SQL中為每個使用a的語句得到一個列表達式? : ? : 表達式另一側的""是因為SQL抱怨CASE語句有多個null。

很明顯 - 這個解決方案,除了像罪一樣丑陋之外,還有多少列可用於你進行這些假比較,實際上L2S映射了多少獨特的比較。

  1. Team,UpdateComments,State是空字符串或null。 所以你應該為這兩種情況賦予相同的價值。
  2. 如果使用默認比較器,則UpdateMessage不同,因此對象不同。 所以你可以連接而不是聯合。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM