пʼятниця, 7 січня 2011 р.

Linq To Sql - Хранимые Процедуры - такой в наших списках не значится...

Проблемма: при добавлении некоторых хранимых процедур в .dbml файл, генерируеться метод-обёртка с неправильной сигнатурой




Натолкнулся на интересное поведение .NET рантайма в ответ на попытку зарегистрировать ХП в LINQ To SQL классе.
Процедура вытаскивает некоторые данные из базы и формирует xml строку (FOR XML EXPLICIT), которую и возвращает.
.NET же упорно генерирует метод, который возвращает целочисельное значение :-(
Первое что пришло на ум - вручную подправить код дизайнера - набросал класс-обёртку для возвращаемой xml-строки, и исправил собственно вызывающий процедуру метод:

[DataContract()]
public partial class spRpt_StaffAnnualHolCalendarResult
{

private string _XML_F52E2B61_18A1_11d1_B105_00805F49916B;

public spRpt_StaffAnnualHolCalendarResult()
{
}

[Column(Name="[XML_F52E2B61-18A1-11d1-B105-00805F49916B]", Storage="_XML_F52E2B61_18A1_11d1_B105_00805F49916B", DbType="NText", UpdateCheck=UpdateCheck.Never)]
[DataMember(Order=1)]
public string XML_F52E2B61_18A1_11d1_B105_00805F49916B
{
get
{
return this._XML_F52E2B61_18A1_11d1_B105_00805F49916B;
}
set
{
if ((this._XML_F52E2B61_18A1_11d1_B105_00805F49916B != value))
{
this._XML_F52E2B61_18A1_11d1_B105_00805F49916B = value;
}
}
}
}


и:
[Function(Name="dbo.spRpt_StaffAnnualHolCalendar")]
public ISingleResult spRpt_StaffAnnualHolCalendar([Parameter(Name="SessionId", DbType="UniqueIdentifier")] System.Nullable sessionId, [Parameter(Name="ScreenID", DbType="TinyInt")] System.Nullable screenID, [Parameter(Name="StartTime", DbType="SmallDateTime")] System.Nullable startTime, [Parameter(Name="NR_Denied", DbType="TinyInt")] ref System.Nullable nR_Denied)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), sessionId, screenID, startTime, nR_Denied);
nR_Denied = ((System.Nullable)(result.GetParameterValue(3)));
return ((ISingleResult)(result.ReturnValue));
}

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

Рытье в сети и последующие эксперименты показали, что такую подлянку .NET может подсунуть, если в процедуре используються временные объекты (такие как временная таблица), или - некорректное приведение типов (к примеру cast(myFieldValue as nvarchar(50)), если myFieldValue потенциально может быть NULL).

Естественно, лучший способ избежать подобной проблеммы - грамотно писать процедуры, однако в моём случае ХП унаследованы из старого проекта, посему имеем что имеем.
Решение, пускай и не очень кошерное - но действенное, подсказал один добрый индус (к сожалению не запомнил его имени) - раз рантайм такой умный - сам решает чего должна возвращать процедура - значит надо лишить его этого права - создаём процедуру пустышку - стаким же именем и сигнатурой - что и существующая строптивая процедура. Скармливаем пустышку рантайму, проверяем - правильно ли все в дизайнере, и если всё ок - возвращаем обратно оригинальную процедуру.

Уточнение: перед скармливанием процедуры-пустышки - из dbml файла надо удалить ссылку на старую хп, и перезагрузить вижуалку - простого реконекта к базе - недостаточно для правильного подключения процедуры :-(. Как гриться - Майкрософт всё делает для упрощения жизни программиста :-)

Немає коментарів:

Дописати коментар