DeriveParameters для OleDbProvider. Часть II
По итогам краткого энергического совещания было принято решение: несмотря на всю подлость со стороны авторов Jet4.0 на провокации не поддаваться и привести инфраструктуру к виду, в которой вызов виртуального метода DeriveParameters в нашем драйвере для MS Access будет работать так же, как и для MS SQL Server, и для Oracle. Я, признаться, уже стал забывать ADOX, да и неудобно использовать его в .NET, медленно. Пораскинув, решение нашёл.
Решение заключается в использовании OleDbConnection.GetOleDbSchemaTable. Последовательно получая текст сохранённого запроса и выполняя отображение имён параметров на поля таблиц (а для Jet4.0 параметр OleDbSchemaGuid.Procedure_Parameters не поддерживается тоже), получаем типы и имена параметров. То есть, в точности то, что делает DeriveParameters для нормальных систем управления базами данных.
В итоге получается примерно так:
public override void DeriveParameters(IDbCommand Command)
{
using (OleDbConnection conn = new OleDbConnection(BaseSolutionProperties.ConnectionString))
{
conn.Open();
DataTable dt = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Procedures, new object[]{null, null, Command.CommandText});
if (dt.Rows.Count != 1)
throw new IndexOutOfRangeException(Command.CommandText);
DataRow row = dt.Rows[0];
Regex regex = new Regex(@"\[\@(?<param>[A-Za-z]+)\]");
string text = (string)row.ItemArray[4];
MatchCollection matches = regex.Matches(text);
if (matches.Count > 0)
{
Command.Parameters.Clear();
foreach (Match match in matches)
{
string paramName = match.Groups["param"].Value;
Triple<string, OleDbType, int> typeAndSize = GetParamInfo(row, paramName, conn);
OleDbParameter param;
if (typeAndSize.Third == 0)
param = new OleDbParameter(String.Format("[@{0}]", paramName), typeAndSize.Second);
else
param = new OleDbParameter(String.Format("[@{0}]", paramName), typeAndSize.Second, typeAndSize.Third);
Command.Parameters.Add(param);
}
}
}
}
...
private static Hashtable m_TableDefs = Hashtable.Synchronized(new Hashtable());
private static object m_HashSync = new object();
private static Triple<string, OleDbType, int> GetParamInfo(DataRow Row, string ParamName, OleDbConnection Conn)
{
string procName = (string)Row.ItemArray[2];
string tabName = null;
const string ins = "sp_Insert";
if (procName.Contains(ins))
tabName = procName.Substring(procName.LastIndexOf(ins) + ins.Length);
else
{
string upd = "sp_Update";
if (procName.Contains(upd))
tabName = procName.Substring(procName.LastIndexOf(upd) + upd.Length);
else
{
string del = "sp_Delete";
if (procName.Contains(del))
tabName = procName.Substring(procName.LastIndexOf(del) + del.Length);
}
}
if (String.IsNullOrEmpty(tabName))
return null;
List<Triple<string, OleDbType, int>> cache;
lock(m_HashSync)
if (m_TableDefs.Contains(tabName))
cache = (List<triple<string, OleDbType, int>>)m_TableDefs[tabName];
else
{
cache = new List<triple<string, OleDbType, int>>();
DataTable dt = Conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[]{null, null, tabName, null});
foreach (DataRow row in dt.Rows)
cache.Add(new Triple<string, OleDbType, int>((string)row["COLUMN_NAME"], (OleDbType)row["DATA_TYPE"],
Convert.ToInt32(
(row["character_maximum_length"] is DBNull ? 0 : row["character_maximum_length"]))));
m_TableDefs.Add(tabName, cache);
}
foreach (Triple<string, OleDbType, int> triple in cache)
{
if (triple.First == ParamName)
return triple;
}
return null;
}
Комментариев нет:
Отправить комментарий