尝试导入SqlDataRecord
数据类型的DateTime2
时,我遇到抛出的异常。此代码段中没有抛出任何异常,但后面的异常的原因在以下代码中很明显。
using System;
using Microsoft.SqlServer.Server;
using System.Data.SqlClient;
using System.Data;
using System.Web.UI.WebControls;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics;
namespace Testing123
{
public class Program
{
public static object SQLTParser(SqlMetaData smd, string val)
{
TypeCode systc = Parameter.ConvertDbTypeToTypeCode(smd.DbType);
try
{
return Convert.ChangeType(val, systc);
}
catch (Exception ex)
{
if (ex is InvalidCastException || ex is FormatException || ex is OverflowException)
{
Console.WriteLine("Exception reached casting " + val + " to " + Type.GetType("System." + Enum.GetName(typeof(TypeCode), systc)) + ": " + ex.Message + ex.ToString()); //smd.GetType().Name
return null;
}
else
{
Console.WriteLine("Null value exception");
return null;
}
}
}
public static void Main()
{
SqlMetaData sqmd = new SqlMetaData("dt", SqlDbType.DateTime2, 27, 7);
SqlDataRecord sdr = new SqlDataRecord(sqmd);
sdr.SetValue(0, SQLTParser(sqmd, "2017-01-12 01:23:12.3456789"));
//set BreakPoint
//sdr -> Non-Public members -> _columnMetaData[0] -> Precision = 27
//sdr -> Non-Public members -> _columnSmiMetaData[0] -> Non-Public members -> Precision = 0
}
}
}
如上所述,如果您设置断点并按照MS Visual Studio *中的指示进行监视,则精确度不会匹配columnMetaData和columnSmiMetaData,而第二个此类条目(!!)会抛出异常:
记录“2”的字段“dt”的元数据与原始记录的元数据不匹配。
匹配
引发的异常由于MetadataUtilsSmi.IsCompatible
的归还本质上,记录2的字段元数据中的精度与记录1的SmiMetaData
中的精度不匹配。在记录1中,MD和SMD也不匹配,但基于逻辑Microsoft正在使用IEnumerator
'd SqlDataRecord
,它在第2条记录之前不会成为问题。
这是MS的错误吗?或者有办法强制SmiMetaData
的精度值?或者忽略ValueUtilsSmi
中的特定字段检查?指定SqlMetaData sqmd = new SqlMetaData("dt", SqlDbType.DateTime2, 0, 7);
允许解析继续进行,但从数据中删除亚秒精度。
简而言之,我是如何尝试将数据发送到数据库的。如果这部分不是一个完整的例子,请道歉。
public class FullStreamingDataRecord : IEnumerable<SqlDataRecord>
{
private string _filePath;
public bool _hasHeader { get; private set; }
private ParserDict _pd; //notably has colStructure which is an array of SqlMetaData[]
public FullStreamingDataRecord(string FilePath, ParserDict pd)
{
_filePath = FilePath;
_pd = pd;
_hasHeader = true;
}
public static object SQLTParser(SqlMetaData smd, string val)
{
TypeCode systc = Parameter.ConvertDbTypeToTypeCode(smd.DbType);
try
{
return Convert.ChangeType(val, systc);
}
catch (Exception ex)
{
if (ex is InvalidCastException || ex is FormatException || ex is OverflowException)
{
Console.WriteLine("Exception reached casting " + val + " to " + Type.GetType("System."+Enum.GetName(typeof(TypeCode),systc)) + ": " + ex.Message + ex.ToString()); //smd.GetType().Name
return null; //smd.TParse(val);
}
else
{
Console.WriteLine("Null value exception casting...attempting a different method");
return null; smd.TParse(val);
}
}
}
public IEnumerator<SqlDataRecord> GetEnumerator()
{
int len = this._pd.colStructure.Length;
StreamReader fileReader = null;
try
{
using (fileReader = new StreamReader(this._filePath))
{
string inputRow = "";
string[] inputColumns = new string[len];
if (_hasHeader && !fileReader.EndOfStream)
{
inputRow = fileReader.ReadLine(); //and ignore
}
while (!fileReader.EndOfStream)
{
string temp = "";
inputRow = fileReader.ReadLine();
inputColumns = inputRow.Split(new char[]{','},len);
SqlDataRecord dataRecord = this._pd.colStructure
for (int j = 0; j < len; j++) { // i = counter for input columns
string currentKey = this._pd.colStructure[j].SqlMetaData.Name;
string curval = inputColumns[j];
var ty = this._pd.colStructure[j].SqlMetaData; //.DbType;
dataRecord.SetValue(j, SQLTParser(ty, curval));
// dataRecord.GetSqlMetaData(j).Adjust(dataRecord.GetValue(j));
}
yield return dataRecord;
}
}
}
// no catch block allowed due to the "yield" command
finally
{
fileReader.Close();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
我在我的Main()
中调用它using (SqlConnection conn = new DBConnect().conn)
{
conn.Open();
SqlCommand importProc = new SqlCommand("tvp_"+pd.tableDestination, conn);
importProc.CommandType = CommandType.StoredProcedure;
importProc.CommandTimeout = 300;
SqlParameter importTable = new SqlParameter();
importTable.ParameterName = "@ImportTable";
importTable.TypeName = "dbo.tt_"+pd.tableDestination;
importTable.SqlDbType = SqlDbType.Structured;
importTable.Value = new FullStreamingDataRecord(fn, pd);
importProc.Parameters.Add(importTable);
importProc.ExecuteNonQuery(); //this line throws the exception
}
抱歉不Console.WriteLine
这些手表的价值。
不幸的是,似乎使用Reflection的sdr.GetType()。GetProperties()来保护这些参数不受检查,即使设置了适当的BindingFlags也是如此。但至少你可以在调试模式下看到这些值!