我在Server中有一个用户定义的函数,它接受一个TVP (表值参数)作为参数。在EF中,如何从C#调用这样的函数?
我尝试使用ObjectContext.CreateQuery<>
方法,但得到了以下错误:
函数'QueryByParam‘的参数'param’无效。参数只能是可以转换为Edm标量类型的类型。
也尝试了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返回,而不是消耗的结果。
发布于 2020-09-07 09:09:14
您可以使用(类似于EF6中的aproach )来实现它,但是您不能获得一个IQueryable。这两个例子都在下面。
实体框架核心
将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; }
}
DTO以匹配sql (也与表相同):
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();
}
}
实体框架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();
}
}
发布于 2020-09-09 04:01:18
AdventureWorks示例数据库有一个表值函数dbo.ufnGetContactInformation,它的返回类型也可以表示为另一个复杂类型。
[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函数:
// 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实体中是可组合的。它可以称为:
[TestMethod]
public void CallTableValuedFunction()
{
using (AdventureWorks database = new AdventureWorks())
{
IQueryable<ContactInformation> employees = database.ufnGetContactInformation(1).Take(2);
Assert.IsNotNull(employees.Single());
}
}
上面的ufnGetContactInformation调用和接受调用将被转换为一个单一的SQL查询:
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
https://stackoverflow.com/questions/63742915
复制相似问题