通过Entity Framework将表值类型传递给SQL Server存储过程

我在SQL Server中创建了一个用户定义的表类型:

CREATE TYPE dbo.TestType AS TABLE ( ColumnA int, ColumnB nvarchar(500) ) 

我正在使用存储过程将记录插入数据库:

 create procedure [dbo].[sp_Test_CustomType] @testing TestType READONLY as insert into [dbo].[myTable] select ColumnA, ColumnB from @testing 

我想使用EF来执行此存储过程,但问题是:如何将用户定义的表传递给存储过程?

我尝试将存储过程添加到模型中,但我无法在更新的上下文中找到所需的存储过程。

我要做的是对表执行批量插入,这是我目前使用的方法:

 List itemToInsertToDB = //fetchItems; foreach(items i in itemToInsertToDB) { context.sp_InsertToTable(i.ColumnA, i.ColumnB) } 

目前,我使用foreach循环遍历列表以将项目插入到DB,但如果列表中有很多项目,那么就会出现性能问题,因此,我正在考虑将列表传递给存储过程并在里面插入。

那么如何解决这个问题呢? 或者有更好的方法吗?

假设您要发送一个包含一列GUID的表。

首先,我们需要使用SqlMetaData创建一个结构,它表示表(列)的模式。

 var tableSchema = new List(1) { new SqlMetaData("Id", SqlDbType.UniqueIdentifier) }.ToArray(); 

接下来,使用SqlDataRecord创建与模式匹配的记录列表。

 var tableRow = new SqlDataRecord(tableSchema); tableRow.SetGuid(0, Guid.NewGuid()); var table = new List(1) { tableRow }; 

然后创建SqlParameter :

 var parameter = new SqlParameter(); parameter.SqlDbType = SqlDbType.Structured; parameter.ParameterName = "@UserIds"; parameter.Value = table; var parameters = new SqlParameter[1] { parameter }; 

然后使用Database.SqlQuery简单地调用存储过程。

 IEnumerable result; using (var myContext = new DbContext()) { result = myContext.Database.SqlQuery("GetUsers", parameters) .ToList(); // calls the stored procedure // ToListAsync(); // Async { 

在SQL Server中,创建用户定义的表类型(我用TTV,表类型值后缀):

 CREATE TYPE [dbo].[UniqueidentifiersTTV] AS TABLE( [Id] [uniqueidentifier] NOT NULL ) GO 

然后将类型指定为参数(不要忘记,表类型值必须是只读的!):

 CREATE PROCEDURE [dbo].[GetUsers] ( @UserIds [UniqueidentifiersTTV] READONLY ) AS BEGIN SET NOCOUNT ON SELECT u.* -- Just an example :P FROM [dbo].[Users] u INNER JOIN @UserIds ids On u.Id = ids.Id END 

我建议您不要使用存储过程来插入批量数据,而只是依赖于Entity Framework插入机制。

 List itemToInsertToDB = //fetchItems; foreach(items i in itemToInsertToDB) { TestType t = new TestType() { ColumnA = i.ColumnA, ColumnB = i.ColumnB }; context.TestTypes.Add(t); } context.SaveChanges(); 

entity framework将巧妙地在单个事务中执行那些插入,并且(通常)在单个查询执行中执行,这几乎等于执行存储过程。 这是更好的,而不是仅仅依靠存储过程来插入大量数据。