如何将数据表从C#传递到SQL Server存储过程

如何解决如何将数据表从C#传递到SQL Server存储过程

我正在开发一个视频游戏锦标赛处理站点。 尝试获取具有指定参数的用户(他们上次登录本地电子咖啡馆的城市以及他们玩过的游戏)。 为了获得最佳性能,我从编写存储过程及其工作开始。 但是,当从代码中调用时,会引发异常。

Exception.Message:列,参数或变量@cityIds。 :找不到数据类型dbo.CityIds。

SQL

CREATE TYPE [dbo].[CityIds] AS TABLE(
  [Id] [uniqueidentifier] NOT NULL
)
GO
ALTER   PROCEDURE [dbo].[spGetUsersByCityAndGame] 
  @gameProcessName NVARCHAR(50),@cityIds       [CityIds] READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT users.Id
FROM AspNetUsers users WITH( NOLOCK )
JOIN
( -- select below finds last log entry by startDateTime column for each user
  SELECT authLog1.*
  FROM AuthenticationLog authLog1 WITH( NOLOCK )
  LEFT OUTER JOIN
  AuthenticationLog authLog2 WITH( NOLOCK )
  ON authLog1.ClientId=authLog2.ClientId
     AND authLog1.StartDateTime<authLog2.StartDateTime
  WHERE authLog2.ClientId IS NULL
) lastAuthLog
ON users.Id=lastAuthLog.ClientId
    JOIN
    Club club
    ON lastAuthLog.ClubId=club.Id
        JOIN
        City city
        ON club.CityId=city.Id
            JOIN
            ProcessLogs processLog
            ON lastAuthLog.Id=processLog.AuthenticationLogId
            INNER JOIN @cityIds cids on city.Id = cids.Id
WHERE users.Birthday IS NOT NULL
      AND users.PhoneNumber IS NOT NULL
      AND users.UserName IS NOT NULL
      AND users.Email IS NOT NULL
      AND users.FullName IS NOT NULL
      AND processLog.ProcessName=@gameProcessName;
END;

C#

private async Task<List<ApplicationUser>> GetUserByParameters(Guid gameId,IEnumerable<Guid> citiesIds)
{
    Game game = await _gamesRepository.GetAsync(gameId);

    SqlParameter gameNameParam = new SqlParameter("@gameProcessName",SqlDbType.NVarChar,50)
    {
        Value = (object)game.ExecutableName ?? DBNull.Value
    };

    List<SqlDataRecord> table = new List<SqlDataRecord>();

    foreach (Guid cityId in citiesIds)
    {
        SqlDataRecord tableRow = new SqlDataRecord(new SqlMetaData[] { new SqlMetaData("Id",SqlDbType.UniqueIdentifier) });

        tableRow.SetGuid(0,cityId);

        table.Add(tableRow);
    }

    SqlParameter citiesIdsParam = new SqlParameter
    {
        TypeName = "[dbo].[CityIds]",SqlDbType = SqlDbType.Structured,ParameterName = "@cityIds",Value = table,};

    string sql = @"EXECUTE dbo.spGetUsersByCityAndGame @gameProcessName,@cityIds";

    List<ApplicationUser> users = await _dbContext.Users.FromSqlRaw(sql,gameNameParam,citiesIdsParam).ToListAsync();

    return users;
}

解决方法

如果您要执行“基于集合”的sql,则可以将DataTable“转换”为xml(通过伪数据集)

            System.Data.DataTable dbfacs = System.Data.Common.DbProviderFactories.GetFactoryClasses(); /* replace this with YOUR datatable code */
            System.Data.DataSet ds1 = new DataSet();
            ds1.Tables.Add(dbfacs);
            string xml = ds1.GetXml();

现在将这个xml发送给您的存储过程。在存储过程中,您将把XML“切碎”到@variable或#temp表中……并从那里进行CUD(创建/更新/删除),或者(根据需要)执行JOINS或EXISTS子句在@variable或#temp表上。

在此处查看完整示例:

https://www.sqlservercentral.com/articles/the-zero-to-n-parameter-problem-sql-server-2005-and-up-update

一般示例:(使用Northwind数据库)(此处的DDL:https://github.com/Microsoft/sql-server-samples/tree/master/samples/databases/northwind-pubs

IF EXISTS (
            SELECT * FROM INFORMATION_SCHEMA.ROUTINES
            WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'uspCustomerFindByXml'  
        )   
BEGIN
    DROP PROCEDURE [dbo].[uspCustomerFindByXml]
END

GO

CREATE PROCEDURE dbo.uspCustomerFindByXml (
    @xmlSource xml,@numberRowsAffected int output  --return
)

AS 

SET NOCOUNT ON 

DECLARE @errorTracker int -- used to "remember" the @@ERROR

DECLARE @updateRowCount int
DECLARE @insertRowCount int 


-- build a table (variable table) to store the xml-based result set
DECLARE @CustomerHolder TABLE (  
    identityid int IDENTITY (1,1),CustomerID varchar(6) 
)


INSERT @CustomerHolder
    (
        CustomerID 
    )
SELECT 
    T.parameter.value('(CustomerID)[1]','varchar(6)') AS CustomerID

FROM @xmlSource.nodes('/CustomersDS/Customers') AS T(parameter);



select * from @CustomerHolder



SET NOCOUNT OFF


Select @updateRowCount = @@ROWCOUNT

SELECT cust.CustomerID,cust.CompanyName,cust.ContactName FROM

    dbo.Customers cust
WHERE
    exists (   select null from @CustomerHolder holder where ltrim(rtrim(upper(holder.CustomerID))) = ltrim(rtrim(upper(cust.CustomerID)))   )

Select @insertRowCount = @@ROWCOUNT

select @numberRowsAffected = @insertRowCount + @updateRowCount

--select * from Customers

SET NOCOUNT OFF


GO




GRANT EXECUTE on dbo.uspCustomerFindByXml TO public



GO





declare @numberRowsAffected int

EXEC dbo.uspCustomerFindByXml
'

<CustomersDS>
  <Customers>
    <CustomerID>ALFKI</CustomerID>
  </Customers>
  <Customers>
    <CustomerID>ANATR</CustomerID>
  </Customers>
  <Customers>
    <CustomerID>ANTON</CustomerID>
  </Customers>
</CustomersDS>

',@numberRowsAffected OUT

print '/@numberRowsAffected/'
print @numberRowsAffected
print ''


GO

这里也是显示“基本知识”的链接。来自微软:

https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/specifying-xml-values-as-parameters

额外:

此“样式”也可以用于CRUD功能。您也可以通过在切碎的xml上加入或​​存在的位置来创建/读取/更新/删除。

下面的CU(创建/更新)通用示例:

IF EXISTS (
            SELECT * FROM INFORMATION_SCHEMA.ROUTINES
            WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'uspTitleUpdate'  
        )   
BEGIN
    DROP PROCEDURE [dbo].[uspTitleUpdate]
END

GO

CREATE PROCEDURE dbo.uspTitleUpdate (
    @xmlSource xml,@numberRowsAffected int output  --return
)

AS 

SET NOCOUNT ON 

DECLARE @errorTracker int -- used to "remember" the @@ERROR

DECLARE @updateRowCount int
DECLARE @insertRowCount int 


-- build a table (variable table) to store the xml-based result set
DECLARE @TitleHolder TABLE (  
    identityid int IDENTITY (1,title_id varchar(6),title varchar(80),type varchar(32),pub_id varchar(32),price money,advance money,royalty varchar(32),ytd_sales varchar(32),notes TEXT,pubdate datetime
)


INSERT @TitleHolder
    (
        title_id,title,[type],pub_id,price,advance,royalty,ytd_sales,notes,pubdate
    )
SELECT 
    T.parameter.value('(title_id)[1]','varchar(6)') AS title_id,T.parameter.value('(title)[1]','varchar(80)') AS title,T.parameter.value('(type)[1]','varchar(32)') AS [type],T.parameter.value('(pub_id)[1]','varchar(32)') AS pub_id,T.parameter.value('(price)[1]','money') AS price,T.parameter.value('(advance)[1]','money') AS advance,T.parameter.value('(royalty)[1]','varchar(32)') AS royalty,T.parameter.value('(ytd_sales)[1]','varchar(32)') AS ytd_sales,T.parameter.value('(notes)[1]','varchar(max)') AS notes,dbo.udf_convert_xml_date_to_datetime (T.parameter.value('(pubdate)[1]','varchar(64)') ) AS pubdate
FROM @xmlSource.nodes('/TitlesDS/Titles') AS T(parameter);


/* 
select * from @TitleHolder
*/


SET NOCOUNT OFF


Update 
    titles 
set 
    title = tu.title,[type]  = tu.[type],pub_id = tu.pub_id,price = tu.price,advance  = tu.advance,royalty  = tu.royalty,ytd_sales  = tu.ytd_sales,notes  = tu.notes,pubdate  = tu.pubdate 
FROM
    @TitleHolder tu,titles
WHERE
    ltrim(rtrim(upper(titles.title_id))) = ltrim(rtrim(upper(tu.title_id)))


Select @updateRowCount = @@ROWCOUNT

INSERT INTO titles
    (
        title_id,pubdate
    )
Select
    title_id,pubdate
FROM
    @TitleHolder tu
WHERE
    not exists (   select null from dbo.titles innerRealTable where ltrim(rtrim(upper(innerRealTable.title_id))) = ltrim(rtrim(upper(tu.title_id)))   )

Select @insertRowCount = @@ROWCOUNT

select @numberRowsAffected = @insertRowCount + @updateRowCount

--select * from titles

SET NOCOUNT OFF


GO




GRANT EXECUTE on dbo.uspTitleUpdate TO public



GO





/* 


declare @numberRowsAffected int

EXEC dbo.uspTitleUpdate
'

<TitlesDS>
  <Titles>
    <title_id>BU1032</title_id>
    <title>The Busy Executives Database Guide</title>
    <type>business    </type>
    <price>19.99</price>
    <pubdate>2013-12-10T13:42:27.020604-05:00</pubdate>
  </Titles>
  <Titles>
    <title_id>BU1111</title_id>
    <title>Cooking with Computers: Surreptitious Balance Sheets</title>
    <type>business    </type>
    <price>11.95</price>
    <pubdate>2013-12-10T13:42:27.021604-05:00</pubdate>
  </Titles>
  <Titles>
    <title_id>BU2075</title_id>
    <title>You Can Combat Computer Stress!</title>
    <type>business    </type>
    <price>2.99</price>
    <pubdate>2013-12-10T13:42:27.021604-05:00</pubdate>
  </Titles>
</TitlesDS>

',@numberRowsAffected OUT

print '/@numberRowsAffected/'
print @numberRowsAffected
print ''

*/

GO

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-