英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论