【问题标题】:How to join a table to itself in EF core?如何在 EF 核心中将表连接到自身?
【发布时间】:2019-09-15 19:35:17
【问题描述】:

我有一个表(“ProductParameter”)将两个表(“Product”和“Parameter”)链接在一起,它有字段 Id、ProductId、ParameterId、Value,每个 ParameterId 都有一个集合 [Value] 我需要过滤集合首先由两个 ParameterId(其中 pp.ParameterId = 4 或 pp1.ParameterId = 2 和 pp1.Value = 'Standard')在过滤一个 ParameterId(其中 pp.ParameterId = 4)后。

例子:

+---------+-------------+------------+---------+
|     ID  |  ProductId  |ParameterId | Value   | 
+---------+-------------+------------+---------+
|     25  |    14       |    2       | Standard|
|     26  |    14       |    3       |  CK45   |
|     27  |    14       |    4       |   63    |
|     28  |    15       |    2       |   XXX   |
|     29  |    15       |    3       |  CK45   |
|     30  |    15       |    4       |   70    |
|     34  |    17       |    2       | Standard|
|     35  |    17       |    3       |  CK45   |
|     36  |    17       |    4       |   40    |
|     37  |    25       |    2       | Standard|
|     38  |    25       |    3       |  CK45   |
|     39  |    25       |    4       |   20    |     
+---------+-------------+------------+---------+-

应该返回:

+-------+
| Value |  
+-------+
|   63  |   
|   40  | 
|   20  | 
+-------+

查询逻辑如下:

 select distinct pp.Value from ProductParameters pp
 join ProductParameters pp1 on pp1.ProductId = pp.ProductId and 
 pp1.ParameterId = 2 and pp1.Value = 'Standard'
 where pp.ParameterId = 4

这是我在 EF 核心中的查询:

public async Task<IEnumerable<ProductParameter>> GetProductDiameters(long id, string param = "Standard")
{
    var value = await _context.ProductParameters
        .Include(p => p.Product)
        .ThenInclude(p => p.ProductParameters.Where(i => i.Value == param))
        .Where(p => p.ParameterId == id)
        .Distinct()
        .ToListAsync();

    return value;
}

抛出异常:

ArgumentException:ThenInclude 属性 lambda 表达式 'p => {from ProductParameter i in p.ProductParameters where ([i].Value == __param_0) select [i]}' 无效。该表达式应表示属性访问:'t => t.MyProperty'。要定位在派生类型上声明的导航,请指定目标类型的显式类型 lambda 参数,例如'(派生 d)=> d.MyProperty'。

错在哪里?

【问题讨论】:

  • .ThenInclude(p => p.ProductParameters.Where(i => i.Value == param)) 应该是 .ThenInclude(p=>p.ProductParameters).Where(i=>i .Product.ProductParameters.Value == param)
  • 比 Where(i=>i.Product.ProductParameters 不包含值
  • 对,它是一个集合。那么正确的语法(而不是 .Where(..))将是 .ForEach(i=>i.Product.ProductParameters=i.Product.ProductParameters.Where(p=>p.Value==param))

标签: c# entity-framework linq-to-entities


【解决方案1】:

EF 抱怨是因为您试图在 .ThenInclude(..) 语句中过滤

var value = await _context.ProductParameters
    .Include(p => p.Product)
    .ThenInclude(p => p.ProductParameters.Where(i => i.Value == param)) //<-- here
    .Where(p => p.ParameterId == id)
    .Distinct()
    .ToListAsync();

这是一个问题,因为 EF 将使用 内部的函数来确定应该预先加载哪些表Include(..)ThenInclude(..) 中的这些函数应该始终指向相关表,并且没有别的 :)

查询的正确方法是这样的:

var value = await _context.ProductParameters
    .Include(p => p.Product)
    .ThenInclude(p => p.ProductParameters) // <- removed the Where clause from here
    .Where(p => p.ParameterId == id)
    .Where(p => p.ProductParameters.Value == param)) //<- and added it here
    .Distinct()
    .ToListAsync();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-22
    • 1970-01-01
    • 2017-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-05
    相关资源
    最近更新 更多