首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >EF:从C#将表值参数传递给用户定义的函数。

EF:从C#将表值参数传递给用户定义的函数。
EN

Stack Overflow用户
提问于 2020-09-04 14:16:52
回答 2查看 2.6K关注 0票数 13

我在Server中有一个用户定义的函数,它接受一个TVP (表值参数)作为参数。在EF中,如何从C#调用这样的函数?

我尝试使用ObjectContext.CreateQuery<>方法,但得到了以下错误:

函数'QueryByParam‘的参数'param’无效。参数只能是可以转换为Edm标量类型的类型。

也尝试了ObjectContext.ExecuteStoreQuery<>方法,得到了同样的错误。无论如何,它不会返回一个IQueryable

样本代码

代码语言:javascript
代码运行次数:0
运行
复制
[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返回,而不是消耗的结果。

EN

回答 2

Stack Overflow用户

发布于 2020-09-07 17:09:14

您可以使用(类似于EF6中的aproach )来实现它,但是您不能获得一个IQueryable。这两个例子都在下面。

实体框架核心

SQL类型用作列表筛选器:

代码语言:javascript
代码运行次数:0
运行
复制
CREATE TYPE [dbo].[Table1Type] AS TABLE(
    [Id] [int] NULL,
    [Name] [nchar](10) NULL
)

SQL UDF:

代码语言:javascript
代码运行次数:0
运行
复制
CREATE FUNCTION [dbo].[Func1] 
(   
    @Ids Table1Type readonly
)
RETURNS TABLE 
AS
RETURN
(
    SELECT * from Table1 where id in (select Id from @Ids)
)

EF上下文:

代码语言:javascript
代码运行次数:0
运行
复制
public class MyContext : DbContext
{
    public DbSet<Table1> Table1 { get; set; }
}

DTO以匹配sql (也与表相同):

代码语言:javascript
代码运行次数:0
运行
复制
public class Table1
{
    public int Id { get; set; }
    public string Name { get; set; }
}

示例:

代码语言:javascript
代码运行次数:0
运行
复制
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();
    }
}

实体框架6

您无法获得IQueryable,但可以将其链接到生成的IEnumerable。

代码语言:javascript
代码运行次数:0
运行
复制
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();
    }
}
票数 9
EN

Stack Overflow用户

发布于 2020-09-09 12:01:18

AdventureWorks示例数据库有一个表值函数dbo.ufnGetContactInformation,它的返回类型也可以表示为另一个复杂类型。

代码语言:javascript
代码运行次数:0
运行
复制
[ComplexType]
public class ContactInformation
{
    public int PersonID { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string JobTitle { get; set; }

    public string BusinessEntityType { get; set; }
}

然后,可以通过以下方式映射ufnGetContactInformation函数:

代码语言:javascript
代码运行次数:0
运行
复制
// Defines table-valued function, which must return IQueryable<T>.
[Function(FunctionType.TableValuedFunction, nameof(ufnGetContactInformation), Schema = dbo)]
public IQueryable<ContactInformation> ufnGetContactInformation(
    [Parameter(DbType = "int", Name = "PersonID")]int? personId)
{
    ObjectParameter personIdParameter = personId.HasValue
        ? new ObjectParameter("PersonID", personId)
        : new ObjectParameter("PersonID", typeof(int));

    return this.ObjectContext().CreateQuery<ContactInformation>(
        $"[{nameof(this.ufnGetContactInformation)}](@{nameof(personId)})", personIdParameter);
}

它的返回类型应该是IQueryable,因此它在LINQ实体中是可组合的。它可以称为:

代码语言:javascript
代码运行次数:0
运行
复制
[TestMethod]
public void CallTableValuedFunction()
{
    using (AdventureWorks database = new AdventureWorks())
    {
        IQueryable<ContactInformation> employees = database.ufnGetContactInformation(1).Take(2);
        Assert.IsNotNull(employees.Single());
    }
}

上面的ufnGetContactInformation调用和接受调用将被转换为一个单一的SQL查询:

代码语言:javascript
代码运行次数:0
运行
复制
exec sp_executesql N'SELECT TOP (2) 
    [top].[C1] AS [C1], 
    [top].[PersonID] AS [PersonID], 
    [top].[FirstName] AS [FirstName], 
    [top].[LastName] AS [LastName], 
    [top].[JobTitle] AS [JobTitle], 
    [top].[BusinessEntityType] AS [BusinessEntityType]
    FROM ( SELECT TOP (2) 
        [Extent1].[PersonID] AS [PersonID], 
        [Extent1].[FirstName] AS [FirstName], 
        [Extent1].[LastName] AS [LastName], 
        [Extent1].[JobTitle] AS [JobTitle], 
        [Extent1].[BusinessEntityType] AS [BusinessEntityType], 
        1 AS [C1]
        FROM [dbo].[ufnGetContactInformation](@PersonID) AS [Extent1]
    )  AS [top]',N'@PersonID int',@PersonID=1
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63742915

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档