C# EF Core 3 DBFunction IQueryable返回类型

C# EF Core 3 DBFunction IQueryable返回类型,c#,entity-framework,dbfunctions,C#,Entity Framework,Dbfunctions,有人知道在efcore中使用DBFunction声明是否可以返回除标量值以外的任何值吗 我正在使用SQL Server将一个站点从EF6迁移到EFCore v3.1.1(从.Net Framework 4.7.2迁移到.Net Core 3.0)。SQL函数有一个两列的表类型返回值。e、 g.(这是实际案例的简化版本): 在EF6模型中,有一个DBFunction声明,返回一个IQueryable,其中ReturnModel是POCO(即,不是映射表实体): 使用声明为 [DbFunction(

有人知道在efcore中使用DBFunction声明是否可以返回除标量值以外的任何值吗

我正在使用SQL Server将一个站点从EF6迁移到EFCore v3.1.1(从.Net Framework 4.7.2迁移到.Net Core 3.0)。SQL函数有一个两列的表类型返回值。e、 g.(这是实际案例的简化版本):

在EF6模型中,有一个DBFunction声明,返回一个IQueryable,其中ReturnModel是POCO(即,不是映射表实体):

使用声明为

[DbFunction("fn_getValues")]
public virtual IQueryable<ReturnModel> fn_getValues(Nullable<int> tenantId, Nullable<int> dataItemId) {
    var tenantIdParameter = tenantId.HasValue ?
        new ObjectParameter("tenantId", tenantId) :
        new ObjectParameter("tenantId", typeof(int));

    var dataItemIdParameter = dataItemId.HasValue ?
        new ObjectParameter("dataItemId", dataItemId) :
        new ObjectParameter("dataItemId", typeof(int));

    return ((IObjectContextAdapter)this).ObjectContext
       .CreateQuery<ReturnModel>("[dbo].[fn_getValues](@tenantId, @dataItemId)", tenantId, dataItemId);
}
[DbFunction(“fn_getValues”)]
公共虚拟IQueryable fn_getValues(可为null的tenantId、可为null的dataItemId){
var tenantId参数=tenantId.HasValue?
新的ObjectParameter(“tenantId”,tenantId):
新的ObjectParameter(“tenantId”,typeof(int));
var dataItemIdParameter=dataItemId.HasValue?
新的ObjectParameter(“dataItemId”,dataItemId):
新的ObjectParameter(“dataItemId”,typeof(int));
返回((IObjectContextAdapter)this).ObjectContext
.CreateQuery(“[dbo].[fn_getValues](@tenantId,@dataItemId)”,tenantId,dataItemId);
}
但我不能让它在EF Core 3中工作。我已尝试将返回类型声明为无键实体,并将DBFunction重新映射到:

[DbFunction("fn_getValues")]
public virtual IQueryable<ReturnModel> fn_getValues(Nullable<int> tenantId, Nullable<int> dataItemId) {
    throw new NotSupportedException();
}
[DbFunction(“fn_getValues”)]
公共虚拟IQueryable fn_getValues(可为null的tenantId、可为null的dataItemId){
抛出新的NotSupportedException();
}
下面是一个如何在愤怒中使用的例子:

int tenantId = <something>;
int filterItemId = <something>;

using (var db = new DBContext) {

    var query = from a in db.ParentItems
    where a.filterItem = filterItemId
    select new {
        a.Id,
        a.Name,
        ModelValues = db.fn_getValues(tenantId, a.Id)
    };

    return await query.ToListAsync(); 
}

inttenantid=;
int filterItemId=;
使用(var db=new DBContext){
var query=来自db.ParentItems中的
其中a.filterItem=filterItemId
选择新的{
a、 身份证,
a、 名字,
ModelValues=db.fn\u getValues(tenantId,a.Id)
};
return wait query.ToListAsync();
}
这总是导致抛出错误

The DbFunction 'fn_getValues' has an invalid return type 'IQueryable<ReturnModel>'. Ensure that the return type can be mapped by the current provider.
DbFunction“fn_getValues”的返回类型“IQueryable”无效。确保返回类型可以由当前提供程序映射。

是否可以从EF Core3返回复杂类型,或者我需要做一些可怕的事情,比如用分隔符将数据字段合并成一个字符串值,并在响应中拆分它们?

EF Core中对TVFs的支持不同,但有一个补偿功能。您可以使用原始SQL查询组合其他LINQ查询表达式:

var searchTerm = ".NET";

var blogs = context.Blogs
    .FromSqlInterpolated($"SELECT * FROM dbo.SearchBlogs({searchTerm})")
    .Where(b => b.Rating > 3)
    .OrderByDescending(b => b.Rating)
    .ToList();


返回一个
IQueryable
,您可以从
fn\u getValues
返回该属性(省略DbFunctionAttribute)。

EF Core中对TVFs的支持不同,但有一个补偿功能。您可以使用原始SQL查询组合其他LINQ查询表达式:

var searchTerm = ".NET";

var blogs = context.Blogs
    .FromSqlInterpolated($"SELECT * FROM dbo.SearchBlogs({searchTerm})")
    .Where(b => b.Rating > 3)
    .OrderByDescending(b => b.Rating)
    .ToList();


返回一个可从
fn\u getValues
返回的
IQueryable
(省略DbFunctionAttribute)。

谢谢David。是的,我使用“FromSqlInterpolated”成功地获取了数据,但在尝试将其中一个参数作为字段从联接表中传递时却没有。我必须首先返回结果集,然后使用FromSqlInterpolated方法对其进行迭代以获得每个子集合。这是预期的方法/行为吗?是。如果没有对TVFs的一流支持,EF将无法生成应用程序以将外部查询列传递给TVF。谢谢David。是的,我使用“FromSqlInterpolated”成功地获取了数据,但在尝试将其中一个参数作为字段从联接表中传递时却没有。我必须首先返回结果集,然后使用FromSqlInterpolated方法对其进行迭代以获得每个子集合。这是预期的方法/行为吗?是。如果没有对TVFs的第一类支持,EF将无法生成应用程序以将外部查询列传递给TVF。
var searchTerm = ".NET";

var blogs = context.Blogs
    .FromSqlInterpolated($"SELECT * FROM dbo.SearchBlogs({searchTerm})")
    .Where(b => b.Rating > 3)
    .OrderByDescending(b => b.Rating)
    .ToList();