c# - EF : Passing a table valued parameter to a user-defined function from C#

标签 c# sql-server entity-framework entity-framework-6 table-valued-parameters

我在 SQL Server 中有一个用户定义的函数,它接受 TVP(表值参数)作为参数。在 EF 中,如何从 C# 调用这样的函数?
我尝试使用方法 ObjectContext.CreateQuery<>但出现以下错误:

The parameter 'param' of function 'QueryByParam' is invalid. Parameters can only be of a type that can be converted to an Edm scalar type.


也试过方法ObjectContext.ExecuteStoreQuery<>并得到同样的错误。它不会返回 IQueryable反正。
示例代码
[DbFunction(nameof(SampleDbContext), "QueryByParam")]
public IQueryable<SecurityQueryRow> QueryByParam(IEnumerable<ProfileType> profiles, bool isActive = false)
{
    DataTable dataTable = ....
    ObjectParameter profilesParam = new ObjectParameter("profileTypeIds", dataTable);

    ObjectParameter isActiveParam = new ObjectParameter("isActive ", isActive);

    return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<SecurityQueryRow>(
            string.Format("[{0}].[{1}](@profileTypeIds, @isActive)", GetType().Name, "QueryByParam"),
            profilesParam,
            isActiveParam);
}
要求是我们需要一个 IQueryable 返回,而不是消耗的结果。

最佳答案

您可以使用 Raw Sql en EF Core、EF6 中的类似方法来实现,但是您无法获得 IQueryable。下面两个例子。
Entity Framework 核心
将其用作列表过滤器的 SQL 类型:

CREATE TYPE [dbo].[Table1Type] AS TABLE(
    [Id] [int] NULL,
    [Name] [nchar](10) NULL
)
SQL UDF:
CREATE FUNCTION [dbo].[Func1] 
(   
    @Ids Table1Type readonly
)
RETURNS TABLE 
AS
RETURN
(
    SELECT * from Table1 where id in (select Id from @Ids)
)
EF 上下文:
public class MyContext : DbContext
{
    public DbSet<Table1> Table1 { get; set; }
}
匹配 sql 类型的 DTO(为简单起见也与 table 相同):
public class Table1
{
    public int Id { get; set; }
    public string Name { get; set; }
}
示例:
static void Main(string[] args)
{
    using (var context = new MyContext())
    {
        // Declare de Structure filter param
        var dt = new DataTable();

        DataTable table = new DataTable();
        table.Columns.Add(new DataColumn("Id", typeof(int)));
        table.Columns.Add(new DataColumn("Name", typeof(string)));
        DataRow row = table.NewRow();
        row["Id"] = 1;
        row["Name"] = "Item";
        table.Rows.Add(row);
        var param = new SqlParameter("@Ids", table) { TypeName = "dbo.Table1Type", SqlDbType = SqlDbType.Structured };

        IQueryable<Table1> query = context.Table1.FromSqlRaw("SELECT * FROM dbo.func1(@Ids)", param);
        var result = query.ToList();
    }
}
Entity Framework 6
您无法获得 IQueryable,但您可以链接到生成的 IEnumerable。
static void Main(string[] args)
{
    using (var context = new MyContext())
    {
        context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);

        // Declare de Structure filter param
        var dt = new DataTable();

        DataTable table = new DataTable();
        table.Columns.Add(new DataColumn("Id", typeof(int)));
        table.Columns.Add(new DataColumn("Name", typeof(string)));
        DataRow row = table.NewRow();
        row["Id"] = 1;
        row["Name"] = "Item";
        table.Rows.Add(row);
        var param = new SqlParameter("@Ids", table) { TypeName = "dbo.Table1Type", SqlDbType = SqlDbType.Structured };

        var query = context.Table1.SqlQuery("SELECT * FROM dbo.func1(@Ids)", param);

        var result = query.ToList();
    }
}

关于c# - EF : Passing a table valued parameter to a user-defined function from C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63742915/

相关文章:

c# - 如何从矩形中获取图像?

c# - 如何将线程异常传播回应用程序异常处理程序

sql-server - 有什么方法/工具可以识别 SQL 服务器中的估计查询运行时间

c# - 将标签列表下拉列表添加到 C# 实体类 - StackOverflow 类型

c# - sql查询中的load和include有什么区别

c# - 在 if block 中将 short 转换为 int

c# - 动态替换 MVC 4 中的标签

c# - 使用 .Include 时, Entity Framework 不会加载相关实体,除非上下文知道相关实体

sql - 如何更新所选数据库中所有过程中公共(public)参数的数据类型

sql - 如何在 SQL Server 列中显示行值?