首頁>Program>source

我的應用程式中有一些查詢(相当多餘),如下所示:

var last30Days = DateTime.Today.AddDays(-30);
from b in Building
let issueSeverity = (from u in Users
                     where u.Building == b
                     from i in u.Issues
                     where i.Date > last30Days
                     select i.Severity).Max()
select new
{
    Building = b,
    IssueSeverity = issueSeverity
}

並且:

var last30Days = DateTime.Today.AddDays(-30);
from c in Countries
let issueSeverity = (from u in Users
                     where u.Building.Country == c
                     from i in u.Issues
                     where i.Date > last30Days
                     select i.Severity).Max()
select new
{
    Country = c,
    IssueSeverity = issueSeverity
}

当然,這是一个簡化的示例.但是,要點是我需要捕获一个日期並過濾一个子查詢.我還需要根据父物件對子查詢进行不同的過濾。

我試圖(基本上)建立了以下功能:

public IQueryable<int?> FindSeverity(Expression<Func<User, bool>> predicate)
{
    var last30Days = DateTime.Today.AddDays(-30);
    return from u in Users.Where(predicate)
           from i in u.Issues
           where i.Date > last30Days
           select i.Severity;
}

使用方法如下:

from c in Countries
let issueSeverity = FindSeverity(u => u.Building.Country == c).Max()
select new
{
    Country = c,
    IssueSeverity = issueSeverity
}

這可以編譯,但是在執行時不起作用.實體框架抱怨 FindSeverity   功能未知。

我尝試了几種不同的表情體操方法,但無济於事。

我需要做些什麼来構成可重用的Entity Framework查詢?

最新回復
  • 4天前
    1 #

    我一直在處理您的問题,但没有最终令人满意的結果.我只会列出我可以找到和理解的几點。

    1)

    我重寫了您的最後一个代碼段(簡化形式,没有投影到匿名型別)...

    var query = from c in Countries
                select FindSeverity(u => u.Building.Country == c).Max();
    

    ...然後使用擴充套件方法語法:

    var query = Countries
                .Select(c => FindSeverity(u => u.Building.Country == c).Max());
    

    現在我们比 FindSeverity(u => u.Building.Country == c).Max()更好看   是威兹威兹   一个 body   ( Expression<Func<Country, T>>   是 T   在這種情况下). (我不確定" body"是否是正確的端子技術,但您知道我的意思:Lambda箭頭右邊的部分=>).当將整个查詢轉換為表達式樹時,此主體將轉換為對函式 int的方法呼叫 . (当您观看 FindSeverity時,可以在除錯器中看到此內容   Expression的财产 : query   是直接在表達式樹中的一个节點,而不是此方法的主體。)由於LINQ to Entities不知道此方法,因此執行失败.在這種lambda表達式的主體中,您只能使用已知函式,例如靜態 FindSeverity中的規範函式   Class。

    System.Data.Objects.EntityFunctions

    構建查詢的可重用部分的一種可能的通用方法是編寫 2)的自定義擴充套件方法 ,例如:

    IQueryable<T>
    

    然後您可以編寫如下查詢:

    public static class MyExtensions
    {
        public static IQueryable<int?> FindSeverity(this IQueryable<User> query,
                                           Expression<Func<User, bool>> predicate)
        {
            var last30Days = DateTime.Today.AddDays(-30);
            return from u in query.Where(predicate)
                   from i in u.Issues
                   where i.Date > last30Days
                   select i.Severity;
        }
    }
    

    如您所见,您被迫使用擴充套件方法語法編寫查詢.我看不到在查詢語法中使用此類自定義查詢擴充套件方法的方法。

    以上示例仅是建立可重用查詢片段的常規模式,但對您問题中的特定查詢並没有真正帮助.至少我不知道如何重新格式化您的 var max1 = Users.FindSeverity(u => u.Building.ID == 1).Max(); var max2 = Users.FindSeverity(u => u.Building.Country == "Wonderland").Max();   方法,使其適合這種模式。

    FindSeverity

    我相信您的原始查詢無法在LINQ to Entities中使用.這樣的查詢...

    3)
    

    ...屬於LINQ to Entities不支援的查詢中的"引用非標量變數"類別. (在LINQ to Objects中有效。)上面查詢中的非標量變數是 from b in Building let issueSeverity = (from u in Users where u.Building == b from i in u.Issues where i.Date > last30Days select i.Severity).Max() select new { Building = b, IssueSeverity = issueSeverity } .如果 Users   表不是空的,可能会出現異常:"無法建立EntityType型別的常量值。在這種情况下,仅支援基本型別(例如Int32,String和Guid')。"< / p>

    您似乎在 Building之間存在一對多關係   和 User   在資料庫中,但是此關聯未在您的實體中完全建模: Building   具有匯航屬性 User   但是 Building   没有 Building的收藏 .在這種情况下,我希望得到一个 Users   在查詢中,類似:

    Join
    

    這不会建立提及非標量變數的異常.但是也许我誤解了你的模型。

    from b in Building join u in Users on u.Building.ID equals b.ID let issueSeverity = (i in u.Issues where i.Date > last30Days select i.Severity).Max() select new { Building = b, IssueSeverity = issueSeverity }

  • 在Grails中使用Spring Security之前/之後的註釋
  • c#:wCF:通用介面的序列化可能吗?