LINQ中的join子句是否可以执行字符串插值?

huangapple go评论64阅读模式
英文:

Is there a way to perform a string interpolation in the join clause using LINQ?

问题

I have to translate a query from a legacy database to LINQ but I'm having some problems with it.
Basically I need to do a left join and the property I want to compare is a composite of properties from the second table.

SELECT A.DATE, B.UNIT, B.PERSON
FROM TABLE1 A 
LEFT JOIN TABLE2 B ON A.KEY = CONCAT(B.UNIT, B.CONTRACT, B.VARIABLE)
WHERE B.DATE = someDate

So far I have tried to create this way, but without success:

var date = someDate;

from a in _context.Table1

join b0 in _context.Table2 on a.Key equals $"{b0.Unit}{b0.Contract}{b0.Variable}" into bGroup
from b in bGroup.DefaultIfEmpty()
where b.Date == date
                    
select new ResponseDto
{
    Date = a.Date,
    Unit = b.Unit,
    Person = b.Person
})
{
  "Message": "The LINQ expression '...' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See 
for more information.", "ErrorName": "InvalidOperationException" }

When removing the string interpolation the query runs without any problem, so I think the problem is in the way I approached this problem. Is there a way to do this?

英文:

I have to translate a query from a legacy database to LINQ but I'm having some problems with it.
Basically I need to do a left join and the property I want to compare is a composite of properties from the second table.

SELECT A.DATE, B.UNIT, B.PERSON
FROM TABLE1 A 
LEFT JOIN TABLE2 B ON A.KEY = CONCAT(B.UNIT, B.CONTRACT, B.VARIABLE)
WHERE B.DATE = someDate

So far I have tried to create this way, but without success:

var date = someDate;

from a in _context.Table1

join b0 in _context.Table2 on a.Key equals $"{b0.Unit}{b0.Contract}{b0.Variable}" into bGroup
from b in bGroup.DefaultIfEmpty()
where b.Date == date
                    
select new ResponseDto
{
    Date = a.Date,
    Unit = b.Unit,
    Person = b.Person
})
{
  "Message": "The LINQ expression '...' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.",
  "ErrorName": "InvalidOperationException"
}

When removing the string interpolation the query runs without any problem, so I think the problem is in the way I approached this problem. Is there a way to do this?

答案1

得分: 1

EF 无法将 string.Format 调用(这是插值字符串转换的内容)转换为 SQL,因为 Format 不仅可以连接字符串。它支持 string.Concat,但只支持接受 2 个参数的重载。我建议尝试以老式的方式进行字符串连接:

join b0 in _context.Table2 on a.Key equals (b0.Unit + b0.Contract + b0.Variable)
英文:

EF cannot translate the string.Format call (which is what the interpolated string gets converted into) into SQL because Format can do much more than just concatenate strings. It does support string.Concat, but only the overload that takes 2 parameters. I would just try string concatenation the old-fashioned way:

join b0 in _context.Table2 on a.Key equals (b0.Unit + b0.Contract + b0.Variable)

答案2

得分: 0

根据您的数据,尝试的方法有:

  • 像D. Stanly建议的那样,在C#查询中连接字段。
  • 根据固定宽度子字符串在C#查询中拆分字段,假设连接的字段是固定宽度的。
  • 如果表中的数据不多,而且您不经常运行此查询,可以将原始数据带入内存中,并在数据上执行C#内存查询。除非您知道搜索的数据非常小且每天执行的查询数量很少,否则不建议使用这种方法。
  • 为查询创建一个SQL视图,其中包含连接的字段,并查询该视图。如果需要进行更新,则不建议使用此方法。
  • 如果数据仅用于读取,请在查询中添加Entity Framework的AsNoTracking()。
  • 如果数据字段中的Unit、Contract或Variable非常有选择性或唯一,则在Entity Framework C#查询中仅选择该字段,然后在您的C#代码中过滤结果。
  • 使用Entity Framework的透传SQL。

总体思路是将带回C#内存的数据子集尽量减小,然后在C#中进行过滤。

注意:如果表中有数百万行数据,您可能需要采用不同的方法。最有可能是采用SQL方法。

英文:

Approaches to try depending on your data:

  • Concatenate the fields in the C# query like D. Stanly suggested
  • Split out the fields in your C# query based on fixed width substrings assuming the concatenated field is fixed width
  • If there is not much data in the tables and you are not running this query very often, bring in the raw data an do an in-memory C# query on the data. This is not recommended unless you know the data searched is very small and the number of queries done per day is small
  • Create a SQL view for the query with the fields concatenated and query that instead. Not recommended if you need to do updates
  • If the data is used read-only, add Entity Framework AsNoTracking() to the query
  • If one of the data fields, Unit, Contract or Variable, are very selective or unique, then select on that field only in Entity Framework C# query and then filter the results in your C# code.
  • Entity Framework pass-through SQL

The general idea is to reduce the subset of data brought back into C# memory to as small as possible and then do filtering in C#.

Note: If this is millions of rows in the tables, you'd need a different approach. Most likely a SQL approach.

huangapple
  • 本文由 发表于 2023年7月6日 21:44:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76629515.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定