在Linq和Entity Framework Core中使用内联表值函数 [英] Use a Inline Table-Valued Functions with Linq and Entity Framework Core
问题描述
我在SQL Server中创建了一个内联表值函数(ITVF),该函数返回一个值表(出于讨论目的而简化查询):
I created an Inline Table-Valued Functions (ITVF) in SQL Server that returns a table of values (query simplified for discussion purposes):
CREATE FUNCTION dbo.VehicleRepairStatus()
RETURNS TABLE
AS
RETURN
SELECT VehicleID, CurrentStatus
FROM VehicleRepairHistory
...
我可以在查询中引用哪些内容
Which I can reference in a query:
SELECT
v.ID, v.Name,
r.CurrentStatus
FROM
Vehicle v
LEFT OUTER JOIN
dbo.VehicleRepairStatus() r on v.ID = r.VehicleID
我希望能够在Linq查询中使用它:
I'd like to be able to use it in Linq query:
var vehicles = await _databaseContext.Vehicles
.Join() // join ITVF here?
.Where(v => v.Type == 'Bus' )
.OrderBy(v => v.Name)
.ToAsyncList();
在某些时候,我可能会更改ITVF以包含一个参数:
At some point, I may change the ITVF to include a parameter:
CREATE FUNCTION dbo.VehicleRepairStatus(@id AS INT)
RETURNS TABLE
AS
RETURN
SELECT VehicleID, CurrentStatus
FROM VehicleRepairHistory
...
WHERE VehicleID = @id
像标量一样调用:
SELECT v.ID, v.Name
,(SELECT val FROM dbo.VehicleRepairStatus(v.ID)) AS CurrentStatus
FROM Vehicle v
Linq查询:
var vehicles = await _databaseContext.Vehicles
.Select( ) // call ITVF here?
.Where(v => v.Type == 'Bus' )
.OrderBy(v => v.Name)
.ToAsyncList();
这两种方法都有可能吗?
Is either approach possible?
推荐答案
Yes, it's possible by utilizing the EF Core 2.1 introduced query types. Following are the required steps:
首先,创建一个类来保存TVF记录(使用正确的数据类型对其进行更新):
First, create a class to hold the TVF record (update it with the correct data types):
public class VehicleRepairStatus
{
public int VehicleID { get; set; }
public int CurrentStatus { get; set; }
}
然后将其注册到您的OnModelCreating
:
modelBuilder.Query<VehicleRepairStatus>();
然后使用Query
和FromSql
方法的组合从数据库上下文中公开它:
Then expose it from your db context using a combination of Query
and FromSql
methods:
public IQueryable<VehicleRepairStatus> VehicleRepairStatus(int id) =>
Query<VehicleRepairStatus>().FromSql($"select * from VehicleRepairStatus({id})");
仅此而已.
现在,您可以像其他任何IQueryable<T>
返回方法一样在LINQ查询中使用它,例如:
Now you can use it inside your LINQ queries like any other IQueryable<T>
returning method, for instance:
from v in db.Vehicles
from r in db.VehicleRepairStatus(v.ID)
select new { v.ID, v.Name, r.CurrentStatus }
FromSql
方法中的选择"使其成为可组合,因此整个查询都转换为SQL并在服务器端执行.
The "select" inside FromSql
method makes it composable, so the whole query is translated to SQL and executed server side.
更新:实际上,如上例所示,当用作相关子查询时,这是行不通的(请参阅).仅当传递常量/变量参数(如
Update: Actually this doesn't work when used as correlated subquery like the above example (see Reference to an ITVF raises a "second operation started on this context before a previous operation completed" exception). It could be used only if passing constant/variable parameters like
from r in db.VehicleRepairStatus(123)
...
请参阅链接中后续帖子的答案,以正确执行相关查询方案.
See the answer to the follow up post from the link for correct implementation for correlated query scenarios.
这篇关于在Linq和Entity Framework Core中使用内联表值函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!