Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Передача списка в хранимую процедуру MS SQL Server

341
03 августа 2008 года
Der Meister
874 / / 21.12.2007
Дамы и господа! Есть CLR хранимая процедура в базе данных MS SQL Server 2005. Необходимо передать туда список/массив значений типа SqlInt64. Заменить передачу списка параметров многократным вызовом процедуры с разными параметрами нельзя - нужен именно список. Так вот, как такое разрулить?
5
03 августа 2008 года
hardcase
4.5K / / 09.08.2005
Цитата: Der Meister
Так вот, как такое разрулить?


Создать собственный CLR-тип данных, инкапсулирующий сисок чего-либо, и уже передавать его.

341
03 августа 2008 года
Der Meister
874 / / 21.12.2007
Смущает мя лишь одно: вроде как, пользовательские типы там могут включать в себя лишь экземляры объектов значащих типов (value-type objects)
5
03 августа 2008 года
hardcase
4.5K / / 09.08.2005
Цитата: Der Meister
Смущает мя лишь одно: вроде как, пользовательские типы там могут включать в себя лишь экземляры объектов значащих типов (value-type objects)


Вот пример:

Код:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, MaxByteSize = 2048)]
public struct SqlIntArray : INullable, IBinarySerialize {

    private int[] _array;

    private bool m_Null;
   
    public override string ToString() {
        if (IsNull)
            return "NULL";
        StringBuilder sb = new StringBuilder();
        sb.Append("{");
        foreach (int number in _array ?? new int[0]) {
            sb.Append(" ");
            sb.Append(number.ToString());
        }
        sb.Append(" }");
        return sb.ToString();
    }

    public bool IsNull {
        get {
            // Put your code here
            return m_Null;
        }
    }

    public static SqlIntArray Null {
        get {
            SqlIntArray h = new SqlIntArray();
            h.m_Null = true;
            return h;
        }
    }

    private static readonly Regex regex = new Regex(@"^\s*{(\s*\d+)*\s*}\s*$",
                    RegexOptions.Compiled);

    public static SqlIntArray Parse(SqlString s) {
        if (s.IsNull)
            return Null;        
        if (regex.IsMatch(s.Value)) {
            SqlIntArray u = new SqlIntArray();
            string[] numbers = s.Value.Split(new char[] { '{', '}', ' ', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
            u._array = Array.ConvertAll<string, int>(numbers, int.Parse);
            return u;
        } else
            return Null;
    }

    // This is a place-holder method
    public int[] ToArray() {
        return _array ?? new int[0];
    }

    #region IBinarySerialize Members

    public void Read(System.IO.BinaryReader r) {
        m_Null = r.ReadBoolean();
        if(!m_Null) {
            int length = r.ReadInt32();
            _array = new int[length];
            for(int i = 0; i < length; ++i) {
                _array = r.ReadInt32();
            }
        }
    }

    public void Write(System.IO.BinaryWriter w) {
        w.Write(m_Null);
        if(!m_Null) {
            int length = _array.Length;
            w.Write(length);
            for (int i = 0; i < length; ++i) {
                w.Write(_array);
            }
        }
    }

    #endregion
}
Хранимка вида:
 
Код:
[Microsoft.SqlServer.Server.SqlProcedure]
public static void StoredProcedure1(SqlIntArray list) {
    foreach(int i in list.ToArray()) {
        SqlContext.Pipe.Send(i.ToString());
    }
}
Теструю кухню скриптом:
 
Код:
DECLARE    @return_value int

EXEC    @return_value = [dbo].[StoredProcedure1]
        @list =  '{12 34 56}'
SELECT    'Return Value' = @return_value

Тип писал "абы работало" там есть кривые места - ограничение размера списка т.к. сиквелу нужно знать сколько будет максимально весить экземпляр объекта:
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, MaxByteSize = 2048)]
Ну и четкая валидация в методе Parse.
341
03 августа 2008 года
Der Meister
874 / / 21.12.2007
Точно, проглядел: если указать в качестве формата сериализации Format.UserDefined, то можно агрегировать даже объекты ссылочных типов (например, List<>).
Спасибо! Бум с размерами разбираться...
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог