Как получить тип.NET Параметра данного StoredProcedure в SQL?

Константа по сравнению с только для чтения :

А быстрое резюме на различиях между 'константой' и 'только для чтения' в C#: 'константа':

  • не Может быть статичным.
  • Значение оценено по телефону время компиляции.
  • Initiailized в объявлении только.

'только для чтения':

  • Может быть или уровень экземпляра или статичный.
  • Значение оценено по телефону время выполнения.
  • Может быть инициализирован в объявлении или кодом в конструкторе.

Исправление: вышеупомянутая константа состояний не может быть статичной. Это - неправильное употребление. Им нельзя было применить статическое ключевое слово, потому что они уже статичны.

, Таким образом, Вы используете константу для статических объектов, которые Вы хотите оцененный во время компиляции.

12
задан MusiGenesis 20 October 2009 в 13:49
поделиться

6 ответов

К сожалению, пока насколько я знаю, это сопоставление не отображается в коде .NET Framework. Раньше я просматривал справочный источник .NET Framework для этого и обнаружил, что внутри кода .NET есть много длинных операторов переключения для каждого типа, таких же, как те, которых вы пытаетесь избежать, но ни один из них не кажется подвергаться внешнему воздействию.

Если вы действительно хотите сопоставить SqlTypes с наибольшей вероятностью. NET, я думаю, лучше всего просто превратить таблицу сопоставления в документации MSDN в код. Обратите внимание, что в таблице MSDN есть (как минимум) две ошибки: №1: нет типа .NET с именем «DateTime2» (я использовал DateTime), а также нет типа с именем «Xml» (я использовал SqlXml).

В любом случае, вот отображение, которое я использовал - использование словаря вместо переключателя для облегчения доступа без отдельного метода.

public static Dictionary<SqlDbType, Type> TypeMap = new Dictionary<SqlDbType, Type>
{
    { SqlDbType.BigInt, typeof(Int64) },
    { SqlDbType.Binary, typeof(Byte[]) },
    { SqlDbType.Bit, typeof(Boolean) },
    { SqlDbType.Char, typeof(String) },
    { SqlDbType.Date, typeof(DateTime) },
    { SqlDbType.DateTime, typeof(DateTime) },
    { SqlDbType.DateTime2, typeof(DateTime) },
    { SqlDbType.DateTimeOffset, typeof(DateTimeOffset) },
    { SqlDbType.Decimal, typeof(Decimal) },
    { SqlDbType.Float, typeof(Double) },
    { SqlDbType.Int, typeof(Int32) },
    { SqlDbType.Money, typeof(Decimal) },
    { SqlDbType.NChar, typeof(String) },
    { SqlDbType.NText, typeof(String) },
    { SqlDbType.NVarChar, typeof(String) },
    { SqlDbType.Real, typeof(Single) },
    { SqlDbType.SmallInt, typeof(Int16) },
    { SqlDbType.SmallMoney, typeof(Decimal) },
    { SqlDbType.Structured, typeof(Object) }, // might not be best mapping...
    { SqlDbType.Text, typeof(String) },
    { SqlDbType.Time, typeof(TimeSpan) },
    { SqlDbType.Timestamp, typeof(Byte[]) },
    { SqlDbType.TinyInt, typeof(Byte) },
    { SqlDbType.Udt, typeof(Object) },  // might not be best mapping...
    { SqlDbType.UniqueIdentifier, typeof(Guid) },
    { SqlDbType.VarBinary, typeof(Byte[]) },
    { SqlDbType.VarChar, typeof(String) },
    { SqlDbType.Variant, typeof(Object) },
    { SqlDbType.Xml, typeof(SqlXml) }, 
};

Обратите внимание на одну вещь, на которую вам нужно обратить внимание - это размер / точность - некоторые типы SQL (например, varchar ) имеют ограничения по размеру, а типы .NET (например, string ]) не надо. Поэтому возможности узнать наиболее вероятный тип .NET недостаточно ... если вы используете это, например, для управления правилами проверки, вам также необходимо иметь возможность запретить пользователям вводить недопустимые (например, слишком большие) значения, зная больше о параметре, например о точности. Обратите внимание, что если вы заглянете внутрь источника SqlClient, они используют специальный код для обработки таких случаев, как установка точности типа Decimal из соответствующей точности SQL.

Обратите внимание, что если единственная причина, по которой вам нужен тип .NET, - это возможность вставлять данные в сохраненный параметр процедуры, вы можете попробовать просто использовать ToString () для всех значений .NET, вставив строку в Value свойства SqlParameter и посмотреть, выполнит ли платформа преобразование / синтаксический анализ за вас. Например, для параметра XML или Date вы можете вместо этого отправить строку.

Кроме того, вместо использования отражения для поиска метода Parse () для каждого типа, поскольку там ' Поскольку известный (и небольшой) список типов, вы можете повысить производительность, используя строго типизированный код синтаксического анализа для каждого типа, как в приведенном ниже коде. (Обратите внимание, что некоторые типы (например, SqlDbType.Udt) не обязательно имеют очевидный метод синтаксического анализа - вам нужно выяснить, как вы хотите их обрабатывать.)

public static Dictionary<SqlDbType, Func<string, object>>  TypeMapper = new Dictionary<SqlDbType, Func<string, object>>
{
    { SqlDbType.BigInt, s => Int64.Parse(s)},
    { SqlDbType.Binary, s => null },  // TODO: what parser?
    { SqlDbType.Bit, s => Boolean.Parse(s) },
    { SqlDbType.Char, s => s },
    { SqlDbType.Date, s => DateTime.Parse(s) },
    { SqlDbType.DateTime, s => DateTime.Parse(s) },
    { SqlDbType.DateTime2, s => DateTime.Parse(s) },
    { SqlDbType.DateTimeOffset, s => DateTimeOffset.Parse(s) },
    { SqlDbType.Decimal, s => Decimal.Parse(s) },
    { SqlDbType.Float, s => Double.Parse(s) },
    { SqlDbType.Int, s => Int32.Parse(s) },
    { SqlDbType.Money, s => Decimal.Parse(s) },
    { SqlDbType.NChar, s => s },
    { SqlDbType.NText, s => s },
    { SqlDbType.NVarChar, s => s },
    { SqlDbType.Real, s => Single.Parse(s) },
    { SqlDbType.SmallInt, s => Int16.Parse(s) },
    { SqlDbType.SmallMoney, s => Decimal.Parse(s) },
    { SqlDbType.Structured, s => null }, // TODO: what parser?
    { SqlDbType.Text, s => s },
    { SqlDbType.Time, s => TimeSpan.Parse(s) },
    { SqlDbType.Timestamp, s => null },  // TODO: what parser?
    { SqlDbType.TinyInt, s => Byte.Parse(s) },
    { SqlDbType.Udt, s => null },  // consider exception instead
    { SqlDbType.UniqueIdentifier, s => new Guid(s) },
    { SqlDbType.VarBinary, s => null },  // TODO: what parser?
    { SqlDbType.VarChar, s => s },
    { SqlDbType.Variant, s => null }, // TODO: what parser?
    { SqlDbType.Xml, s => s }, 
};

Приведенный выше код довольно прост, например :

        string valueToSet = "1234";
        SqlParameter p = new SqlParameter();
        p.SqlDbType = System.Data.SqlDbType.Int;
        p.Value = TypeMapper[p.SqlDbType](valueToSet);
13
ответ дан 2 December 2019 в 06:09
поделиться

Думаю, вам здесь не хватает шага. Первое, что вам нужно сделать, это запросить в базе данных определение хранимой процедуры через вызов select и внутреннее соединение с таблицей sys objects или с помощью оболочки управления. Затем вы можете «вывести» типы параметров на основе возвращенной информации.

Вот MSO lin k, чтобы вы начали

И пример , как запрашивать базу данных структура напрямую

Если вы запустите sql из второго примера для своей базы данных, вы точно увидите, что происходит:

USE AdventureWorks;
GO
SELECT SCHEMA_NAME(SCHEMA_ID) AS [Schema], 
SO.name AS [ObjectName],
SO.Type_Desc AS [ObjectType (UDF/SP)],
P.parameter_id AS [ParameterID],
P.name AS [ParameterName],
TYPE_NAME(P.user_type_id) AS [ParameterDataType],
P.max_length AS [ParameterMaxBytes],
P.is_output AS [IsOutPutParameter]
FROM sys.objects AS SO
INNER JOIN sys.parameters AS P 
ON SO.OBJECT_ID = P.OBJECT_ID
WHERE SO.OBJECT_ID IN ( SELECT OBJECT_ID 
FROM sys.objects
WHERE TYPE IN ('P','FN'))
ORDER BY [Schema], SO.name, P.parameter_id
GO
3
ответ дан 2 December 2019 в 06:09
поделиться

Вы не можете обязательно неявно и точно извлечь правильный .NET CTS («базовый») тип, потому что он может меняться в зависимости от значения в параметре - SqlParameter's .DbType и .SqlDbType являются изменяемыми и явно устанавливаемыми программистом (или механизмом генерации кода). В случае выходного параметра .DbType / .SqlDbType может быть неверным даже после того, как какое-то время было правильным, например, если значение то, что внезапно возвращается, отличается от ожидаемого в терминах .NET. Значения определяются хранилищем данных, и .NET SqlParameter наилучшим образом справляется со своими явными типами. Значение данных SqlParameter следует считать слабо типизированным в терминах .NET (о чем свидетельствует возвращаемое значение свойства parm.Value System.Object).

Лучше всего

  1. Используйте один из методов сопоставления, описанных в других плакатах - конечно, это имеет свое собственное неявное предположение, что тип параметра SQL всегда будет правильным для данных в нем.
  2. возможно, протестируйте значение, возвращаемое из выходного параметра, и предполагаем, что последовательные значения одного вида. Конечно, это действительно зависит от базы данных.
  3. Найдите другую стратегию вместо того, чтобы полагаться на пространство имен Microsoft Sql - в будущем вы можете быть намного счастливее.

Проверка значения для типа .NET CTS будет выглядеть примерно так System.Type t = paramInstance.Value.GetType (); Null вызовет исключение. Вам все равно придется применить его соответствующим образом с помощью переключателя или if / else, если только вы не примените какие-нибудь причудливые техники отражения.

Конечно, это действительно зависит от базы данных.
  • Найдите другую стратегию вместо того, чтобы полагаться на пространство имен Microsoft Sql - в будущем вы можете быть намного счастливее.
  • Проверка значения для типа .NET CTS будет выглядеть примерно так System.Type t = paramInstance.Value.GetType (); Null вызовет исключение. Вам все равно нужно будет преобразовать его соответствующим образом с помощью переключателя или if / else, если только вы не примените какие-то причудливые методы отражения.

    Конечно, это действительно зависит от базы данных.
  • Найдите другую стратегию вместо того, чтобы полагаться на пространство имен Microsoft Sql - в будущем вы можете быть намного счастливее.
  • Проверка значения для типа .NET CTS будет выглядеть примерно так System.Type t = paramInstance.Value.GetType (); Null вызовет исключение. Вам все равно нужно будет преобразовать его соответствующим образом с помощью переключателя или if / else, если только вы не примените какие-то причудливые методы отражения.

    3
    ответ дан 2 December 2019 в 06:09
    поделиться

    Если вы можете разрешить правильный SqlType, Reflection предоставит вам явное приведение к типу .NET. Возвращаемое значение будет лежащим в основе System.Type. Кэширование результата должно компенсировать производительность при первом поиске.

    1
    ответ дан 2 December 2019 в 06:09
    поделиться

    Посмотрите, что они делают в linq to sql t4 , кажется, работают нормально.

    Возможно, вы сможете узнать, что вам нужно, посмотрев на код.

    1
    ответ дан 2 December 2019 в 06:09
    поделиться

    No one else seems to want to tell you, but what you're doing is probably not the best way to do it.

    object correctParam = param.GetNETType().GetMethod("Parse", 
        new Type[] { typeof(string) }).Invoke(value.ToString());
    param.Value = correctParam;
    

    You're saying that you're given a string value, which you know has to be assigned to a parameter, and you want to stuff that value in there any way that it can fit?

    Please consider why you are doing this. You are making the assumption that the following code is right:

    param.Value = NetType.Parse(value.toString())
    

    There's no clear reason why this is better than:

    param.Value = value;
    

    But since you want to do it, it seems safe to assume that you have tried this and found that your real problem is that value isn't the right type for the parameter. Thus you want a magical fix that you can run which will always make sure that value is the right type. What you really want is likely:

    SetParam(param, value);

    Where this function stuffs the value into the parameter. This actually makes things a bit easier if value is not simply of type object as you say, but has a real type (like int or string). This is because you can use method overloading like SetParam(SqlParam param, int value) or generics to infer the value type SetParam(SqlParam param, T value).

    So we know the function you want, what we don't know is why. In most reasonable scenarios you have an idea of the types of the values, and you also have an idea of the type of the parameter. You are asking for a way to cram a value that doesn't match a parameter into a parameter that you don't understand.

    There are two main reasons I can think of for this request:

    1. You in reality know that the types are compatible, and are looking for a general way to do this to avoid writing a lot of code. So you know that you are trying to assign a long to a parameter that is a SqlInt, and are relying on string conversions to get you past the type safety issues.

    2. You don't really understand the code that you are using and are trying to patch in a fix to get something working.

    It's really important to be honest with yourself about which case you are in. If you are in the first case, then you can write a method like SetParam that I described above fairly easily. You will have to write a switch statement (or like the best answer above, a Dictionary lookup). You are going to have to lose precision (casting a long to an int doesn't work for large numbers, but neither will your Parse) but it will work.

    If you're in the second case, stop for a minute. Recognize that you are setting yourself up for more bugs in the future (because converting to and from string will not solve the problems you have of not understanding the types). You know that you need help, which is why you are on Stack Overflow and offering a bounty for help, and you are dealing with a codebase that you don't understand. I can tell right now from your question that you are going to dig yourself a deeper hole than you realize if this is your situation, because you have already refused the best answer (to do a switch statement based on parameter type) for no strong reason.

    So, if you are in the second case, the thing that is going to help you most is not an answer from Stack Overflow, unless you are willing to describe your real problem more completely. What will help you is understanding where the values are coming from (is it UI? Is it a different subsystem, which rules do they follow? Is there a reason the types don't match?) and where they are going (what is the definition of the stored procedure you are calling? What are the parameter types defined as?). I imagine you probably don't even need to go into SQL to find this, as whoever gave you the SqlParam probably already has defined it properly for you. If you defined it, you do indeed need to go to the SQL to figure it out, immediately.

    4
    ответ дан 2 December 2019 в 06:09
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: