我们使用以下代码示例通过存储过程(SQL Server)将数据从我的应用程序发送到外部数据库。
这里我也需要支持MySQL。因此,基于最终用户的数据库选择,我们需要将数据发送到MySQL或SQL Server
c#代码将在另一台机器上运行,而DB服务器将是不同的服务器。
C#代码
using (SqlConnection sqlConnection = new SqlConnection(<<MyConnectionString>>))
{
using (SqlCommand sqlCommand = new SqlCommand(<<StoredProcedureName>>, sqlConnection))
{
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.Add("tblStudent", SqlDbType.Xml).Value = students.ToList().ToXML();
sqlConnection.Open();
sqlCommand.ExecuteNonQuery();
}
}
存储过程
CREATE PROCEDURE `usp_UpdateStudent` (@tblStudent XML)
BEGIN
SET NOCOUNT ON;
INSERT INTO Student(StudentId,StudentName)
SELECT Student.value('(StudentId)[1]', 'nvarchar(100)') as StudentId,
Student.value('(StudentName)[1]', 'nvarchar(100)') as StudentName
FROM
@tblStudent.nodes('/ArrayOfStudent/Student')AS TEMPTABLE(Student)
END
我在网上搜索了如何将xml字符串作为输入参数从c#传递给存储过程。但我没有得到任何具体的答案。
请提供有关如何使用XML作为输入参数创建存储过程的建议,以及如何将XML字符串从c#传递到该文件。
注意:上述代码在SQL Server中按预期工作。当我尝试用MySQL实现相同的功能时,我发现MySQL在存储过程中不支持xml作为输入类型参数。看起来我需要将xml作为普通文本传递并解析存储过程中的文本。
如果有更有效的方法,请告诉我。
答案 0 :(得分:0)
使用Load_File()将xml数据导入局部变量,然后ExtractValue()使用XPath查询XML数据。例如,在下面的代码中,它从xml_content变量中检索学生数:
declare xml_content text;
declare v_row_count int unsigned;
set xml_content = load_file(path);
set v_row_count = extractValue(xml_content, concat('count(', node, ')'))
路径:'C:\ students1.xml',节点:'/ student_list / student'
答案 1 :(得分:0)
我意识到这是一个老问题,但我也没能找到一个好的答案,所以我被迫自己做了一些工作!最终结果似乎有效。根据您的需要进行调整,可以为您提供以下内容:
DELIMITER $$
CREATE procedure `usp_InsertStudent` (ptblStudent text)
BEGIN
declare cnt int;
declare ptr int;
declare rowPtr varchar(100);
set cnt = (extractValue(ptblStudent, 'count(/ArrayOfStudent/Student)'));
set ptr = 0;
while ptr < cnt do
SET ptr = ptr + 1;
SET rowPtr = concat('/ArrayOfStudent/Student[', ptr, ']');
INSERT INTO Student (StudentId,StudentName)
values (extractValue(ptblStudent, concat(rowPtr, '/StudentId')),
extractValue(ptblStudent, concat(rowPtr, '/StudentName')));
end while;
SELECT ptr;
END;
$$
DELIMITER ;
顺便说一句 - 我改变了例程名称(你的例子是插入而不是更新)。
作为解释。如果执行extractValue('/ArrayOfStudent/Student/StudentId')
,则会得到一个结果字符串,其中所有值都以空格分隔。鉴于在MySQL中分割字符串并不是那么容易(在我有限的经验中),逐行提取单个值似乎更好(当有很多字段时尤其如此 - 我首先尝试提取所有字段一旦进入空格分隔的字符串,然后将字符串拆分为单独的临时表,每个临时表都有一个auto_increment id,然后加入id上的临时表,但是当需要三个以上的字段时,这很快变得混乱),因此需要检查行计数,以及while循环的使用。这确实意味着插入成为单个插入,这就是我返回ptr
以指示添加的行数而不是row_count()
(在这种情况下为1!)的原因。
在隐式转换时,我对MySQL的灵活性感到非常高兴:除了字符串之外,我到目前为止还成功测试了整数,双打和DateTimes - 迄今为止还没有必要进行明确的转换。
在更一般的层面上,您的问题也引发了向多个数据提供商编码的问题。几年前,我的一位同事说服我按照部分评论中提出的DbConnection路线行事。事后看来,这是一个错误。问题是,您失去了利用通过其.Net库公开的一个或其他数据库提供程序的特定功能的机会。所以我现在所做的就是你提出的建议:我通过接口定义我的数据访问层;然后,每个数据库提供程序由一个类实现此接口,每个类使用本机.Net库。因此SQL Server实现使用SqlConnection,MySQL实现MySqlConnection,Oracle实现OracleConnection等。通过这种方式,我的应用程序不关心实现细节,但我可以自由地利用一个或另一个db独有的功能。举一个简单的例子:MS SQL服务器允许存储过程返回多个记录集(具有不同的字段),从而允许您在一次调用db中填充复杂的DataSet;我使用的所有其他dbs,每个记录集需要一个过程,因此必须在DAL中构建DataSet。对于应用程序,没有区别,因为接口需要返回DataSet。