簡體   English   中英

使用包含到 EF for SQL IN() 的表達式獲取 LINQ,其中實體上的子屬性等於值

[英]Expression to get LINQ with Contains to EF for SQL IN() where on entities child's property equals value

我有一個簡單的需要,從返回的集合中過濾掉所有父項,其中字段上沒有匹配項,即從字符串中按名稱調用,與呈現的值不匹配。 我所追求的是,​​如果parent對象具有child對象,並且該child對象屬性"foo" (由字符串調用)不等於或等於值bar ,則從集合中適當地過濾parent對象。

這是我的 linq ef 電話

var field = "bar";
var values = new List<string>{"foo","fuYu"};
var dataPage = _aim_context.ae_s_bld_c.AsNoTracking();
var result = dataPage.Where(x => 
                              DbHelper.byPropertyContains(x.udfs, field, values)
                           );
// NOTE `udfs` is a ONE-to-ONE with `ae_s_bld_c`

我希望看到的是類似於 SQL 的東西

SELECT [m].[id],[m.udfs].[bar],
FROM [dbo].[ae_s_bld_c] AS [m]
    INNER JOIN [dbo].[ae_s_bld_c_udf] AS [m.udfs]
        ON ([m].[multitenant_id] = [m.udfs].[multitenant_id])
WHERE ([m].[multitenant_id] = 1.0)
    AND ([m.udfs].[bar] IN ('foo','fuYu')) --< Goal line

我處理這個問題的方法是設置一個表達式來獲取List<string>並生成 SQL。 我已經閱讀了近 50 篇文章和 SO 帖子,但還沒有弄清楚為什么我還沒有得到這個,因為每個人似乎都有不同的想法,而且大多數似乎都不符合 dotnet core 2.1+。

這是我經過多次迭代后目前所坐的。 注意:它與我所追求的略有不同,因為我正在提供我目前的線索。

我當前的上下文 linq 嘗試

//...
dataPage = dataPage.Where(DbHelper.byPropertyContains<ae_s_bld_c>("udfs", field, values));
//...

我認為如果它像我提出的第一個例子會更好,但這就是我已經登陸的原因,因為我有時間將它與x=>x.udfs ,兩者都是x=> funName(x.udfs)x=> x.udfs.funName()

我構建表達式的靜態方法

public static class DbHelper
{
    public static Expression<Func<T, bool>> byPropertyContains<T>(string node, string field, List<string> value) {
//trying to take parent item and get it's property by string name because
// doing the function in linq like x=>x.udfs was not working right
// but that is the prefered I think
        var property_parameter = Expression.Parameter(typeof(T), "x");
        var property = Expression.PropertyOrField(property_parameter, node);
        var selector_parameter = Expression.Parameter(property.Type, "y");
        var selector = Expression.PropertyOrField(selector_parameter, field);
        var methodInfo = typeof(List<string>).GetMethod("Contains", new Type[] {
            typeof(string)
        });
        var list = Expression.Constant(value, typeof(List<string>));
        var body = Expression.Call(methodInfo, list, selector);
        return Expression.Lambda<Func<T, bool>>(body, selector_parameter);
    }
}

更新

根據@NetMage 的要求,我嘗試使用 LINQpad 向后工作。 我想我很接近,但很難用輸出來判斷。 我把它放在這里以供參考。 需要明確的是,孩子的屬性名稱將是名稱的字符串。 最好的結果是我可以有一個像udfs.foo這樣的名稱,如果值包含字符串名稱,我可以在任何級別上進行測試,但從這里開始真的沒問題,

var result = dataPage.Where(x => 
                              DbHelper.byPropertyContains(x.udfs, field, values)
                           );

LINQpad的輸出

讓我們從這里開始。 你需要一個類似這樣的東西

var result = dataPage.Where(x => values.Contains(x.udfs.{field}));

其中field是一個字符串,返回由名稱動態指定的屬性。

在 EF Core 中,您甚至不需要手動處理構建表達式,因為 EF Core 提供了一個特殊的 SQL 可翻譯函數,用於通過名為EF.Property的名稱訪問簡單屬性。

使用該方法,解決方案很簡單:

var result = dataPage
   .Where(x => values.Contains(EF.Property<string>(x.udfs, field)));

暫無
暫無

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

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