Уважаемые коллеги, начал разбираться с RFD и сразу столкнулся с проблемой.
Как читать объекты из БД — понятно, но к сожалению, не совсем понятно, как их туда правильно сохранять при помощи RFD.
Может кто покажет кусочек кода?
Здравствуйте, BVA, Вы писали:
BVA>Уважаемые коллеги, начал разбираться с RFD и сразу столкнулся с проблемой. BVA>Как читать объекты из БД — понятно, но к сожалению, не совсем понятно, как их туда правильно сохранять при помощи RFD. BVA>Может кто покажет кусочек кода?
Вот так можно сделать параметры из объекта за один вызов:
public void AddMyObject(MyObject obj)
{
using (DbManager db = new DbManager())
{
db
.SetSpCommand("p_AddMyObject", db.CreateParameters(obj))
.ExecuteNonQuery();
}
}
Можно каждый параметр создавать отдельно через db.Parameter.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, SiAVoL, Вы писали:
SAV>только вот вроде там если в хранимке были OUTPUT параметры то в объект они не попадали, я там руками подтачивал, помнится
Возможно А что именно подтачивал?
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Возможно А что именно подтачивал?
я писал расширение DBManager, писал давно, на заре знакомства с RFD и давно туда не смотрел. так что может и криво, но работает
Приведу небольшую выдержку
public class DbManagerEx : DbManager
{
/// <summary>
/// Создает параметры для хранимой процедуры,
/// на основе бизнес-объекта
/// </summary>
/// <param name="spName">Имя хранимой процедуры</param>
/// <param name="entity">Бизнес-объект</param>
/// <returns>Массив параметров</returns>public IDbDataParameter[] BuildSPParametrs(string spName,
object entity)
{
IDbDataParameter[] pars =
GetSpParameterSet(spName, false);
object[] values = new object[pars.Length];
MapDescriptor descriptor =
MapDescriptor.GetDescriptor(entity.GetType());
for (int i = 0; i < pars.Length; i++)
{
string pName = GetParametrMapName(pars[i]);
int ord = ((IMapDataReceiver) descriptor).GetOrdinal(pName);
values[i] = ((IMapDataSource) descriptor)
.GetFieldValue(ord, entity);
}
AssignParameterValues(pars, values);
return pars;
}
/// <summary>
/// Выполняет хранимую процедуру с бизнес-обектом параметром
/// </summary>
/// <param name="spName">Имя хранимой процедуры</param>
/// <param name="parametrEntity">
/// Бизнес-объект параметр хранимой процедуры</param>
/// <returns>Число строк, на которые оказала действие
/// хранимая процедура</returns>public int ExecuteSpNonQuery(
string spName,
object parametrEntity)
{
IDbDataParameter[] pars = BuildSPParametrs(spName,
parametrEntity);
int Affected = this
.SetCommand(CommandType.StoredProcedure, spName, pars)
.ExecuteNonQuery();
BackMapParametrs(pars, parametrEntity);
return Affected;
}
/// <summary>
/// Выполняет хранимую процедуру с бизнес-обектом параметром
/// и возвращает бизнес-объект
/// </summary>
/// <param name="bizObjectType">Тип бизнес-объекта</param>
/// <param name="spName">Имя хранимой процедуры</param>
/// <param name="parametrEntity">Объект из которого будут
/// сформированы параметры хранимой процедуры</param>
/// <returns>Бизнес-объект</returns>public object ExecuteSpBizEntity(
Type bizObjectType,
string spName,
object parametrEntity)
{
IDbDataParameter[] pars = BuildSPParametrs(spName,
parametrEntity);
object obj = this
.SetCommand(CommandType.StoredProcedure, spName, pars)
.ExecuteBizEntity(bizObjectType);
BackMapParametrs(pars, parametrEntity);
return obj;
}
private string GetParametrMapName(IDbDataParameter parametr)
{
return parametr.ParameterName.Substring(1);
}
private voidBackMapParametrs(IDbDataParameter[] pars,
object ParametrEntity)
{
MapDescriptor descriptor =
MapDescriptor.GetDescriptor(ParametrEntity.GetType());
foreach (IDbDataParameter p in pars)
if (p.Direction == ParameterDirection.Output ||
p.Direction == ParameterDirection.InputOutput)
{
descriptor[GetParametrMapName(p)].SetValue(
ParametrEntity, p.Value);
}
}
}
функция BackMapParametrs как раз и осуществляет обратное отображение
Здравствуйте, IT, Вы писали:
IT>Там же есть методы InputOutputParameter и OutputParameter. Они разве не работают?
давно это было, может я тогда не раб\зобрался с чем-нибудь. Надо будет посмотреть как-нибудь
... << RSDN@Home 1.1.4 beta 3 >>
Re[2]: RFD Сохранение объектов. Как?
От:
Аноним
Дата:
30.09.04 12:00
Оценка:
Здравствуйте, IT, Вы писали:
IT>
IT>public void AddMyObject(MyObject obj)
IT>{
IT> using (DbManager db = new DbManager())
IT> {
IT> db
IT> .SetSpCommand("p_AddMyObject", db.CreateParameters(obj))
IT> .ExecuteNonQuery();
IT> }
IT>}
IT>
В Вашей статье есть такой пример
void InsertRegion(Region region)
{
using (DbManager db = new DbManager())
{
db
.SetCommand(@"
INSERT INTO Region (
RegionID,
RegionDescription
) VALUES (
@ID,
@Description
)",
db.CreateParameters(region)).
.ExecuteNonQuery();
}
}
Общего с вышеприведенным примером — метод CreateParameters. А как работает этот метод? Ведь, как известно, Reflection может возвращать свойства в любом порядке. Получается, что вместо RegionID может быть помещено Region.Description.
Здравствуйте, <Аноним>, Вы писали:
А>А как работает этот метод? Ведь, как известно, Reflection может возвращать свойства в любом порядке. Получается, что вместо RegionID может быть помещено Region.Description.
прочитайте статью еще раз, обратив внимание на атрибут MapField
... << RSDN@Home 1.1.4 beta 3 >>
Re[4]: RFD Сохранение объектов. Как?
От:
Аноним
Дата:
30.09.04 12:37
Оценка:
Здравствуйте, SiAVoL, Вы писали:
SAV>Здравствуйте, <Аноним>, Вы писали:
А>>А как работает этот метод? Ведь, как известно, Reflection может возвращать свойства в любом порядке. Получается, что вместо RegionID может быть помещено Region.Description. SAV>прочитайте статью еще раз, обратив внимание на атрибут MapField
Да, я тоже так подумал вначале. Но при детальном рассмотрении кода оказалось, что строка запроса нигде не разбирается.
Здравствуйте, <Аноним>, Вы писали:
А>Да, я тоже так подумал вначале. Но при детальном рассмотрении кода оказалось, что строка запроса нигде не разбирается.
А зачем строку? Биндинг по именам спасает от неопределенности порядка.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: RFD Сохранение объектов. Как?
От:
Аноним
Дата:
01.10.04 09:35
Оценка:
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, <Аноним>, Вы писали:
А>>Да, я тоже так подумал вначале. Но при детальном рассмотрении кода оказалось, что строка запроса нигде не разбирается. S>А зачем строку? Биндинг по именам спасает от неопределенности порядка.
А имена откуда получить можно? Только из строки запроса.
Здравствуйте, <Аноним>, Вы писали: А>А имена откуда получить можно? Только из строки запроса.
А ты обратил внимание на атрибут MapField?
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: RFD Сохранение объектов. Как?
От:
Аноним
Дата:
01.10.04 10:48
Оценка:
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, <Аноним>, Вы писали: А>>А имена откуда получить можно? Только из строки запроса. S>А ты обратил внимание на атрибут MapField?
Тогда еще раз объясню ситуацию.
Есть класс
public class Region
{
[MapField("RegionID")]
public int ID;
[MapField("RegionDescription")]
public string Description;
}
Есть запрос вида "INSERT INTO Region (RegionID, RegionDescription) VALUES (@ID, @Description)". Чтобы узнать соответствие параметров — значение следует выполнить сдедующие шаги:
Из строки запроса получить название колонок (RegionID, RegionDescription)
По названиям колонок через Reflection получить значения полей объекта Region
Создать параметры IDbDataParameter
Первый шаг не выполняется
Здравствуйте, <Аноним>, Вы писали:
А>Да, я тоже так подумал вначале. Но при детальном рассмотрении кода оказалось, что строка запроса нигде не разбирается.
просмотрите детально код еще раз и обратите внимание на использование интерфейса System.Data.IDbCommand. Это класс ADO.NET. Его наследникам достаточно дать параметры с правильными именами (чем и занимается RFD, а правильные имена указываются с помощью MapField) и ADO.NET сама все распарсит и выполнит всю черновую работу. В общем RFD это оболчка над ADO.NET, более высокоуровневая, поэтому такими мелочами она не занисмается.
Здравствуйте, <Аноним>, Вы писали:
А> А>Из строки запроса получить название колонок (RegionID, RegionDescription)
делает ADO.NET
А>По названиям колонок через Reflection получить значения полей объекта Region
делает RFD
А>Создать параметры IDbDataParameter
можно сделать самому, можно отдать на откуп RFD А>
А>Первый шаг не выполняется
смотреть фунекцию CreateParameters и иже с нею
Здравствуйте, <Аноним>, Вы писали:
А>Здравствуйте, Sinclair, Вы писали:
S>>Здравствуйте, <Аноним>, Вы писали: А>>>А имена откуда получить можно? Только из строки запроса. S>>А ты обратил внимание на атрибут MapField?
А> Тогда еще раз объясню ситуацию.
А>Есть класс
А>
А>public class Region
А>{
А> [MapField("RegionID")]
А> public int ID;
А> [MapField("RegionDescription")]
А> public string Description;
А>}
А>
А>Есть запрос вида "INSERT INTO Region (RegionID, RegionDescription) VALUES (@ID, @Description)". Чтобы узнать соответствие параметров — значение следует выполнить сдедующие шаги:
А> А>Из строки запроса получить название колонок (RegionID, RegionDescription) А>По названиям колонок через Reflection получить значения полей объекта Region А>Создать параметры IDbDataParameter А>
А>Первый шаг не выполняется
Зачем? Если ты написал
[MapField("RegionID")]
public int ID;
то подразумевается, что везде в запросах параметр соответствующий полю ID бизнес сущности Region будет иметь имя @RegionID. В твою задачу входит не забывать об этом.
Поэтому исходя из твоего описания класса Region следует написать следующий запрос:
INSERT INTO Region (RegionID, RegionDescription) VALUES (@RegionID, @RegionDescription)
В итоге созданные параметры правильно свяжуться по именам.
... << RSDN@Home 1.1.4 beta 3 rev. 190>>
Re[6]: RFD Сохранение объектов. Как?
От:
Аноним
Дата:
01.10.04 11:32
Оценка:
Здравствуйте, SiAVoL, Вы писали:
SAV>Здравствуйте, <Аноним>, Вы писали:
А>>Да, я тоже так подумал вначале. Но при детальном рассмотрении кода оказалось, что строка запроса нигде не разбирается. SAV>просмотрите детально код еще раз и обратите внимание на использование интерфейса System.Data.IDbCommand. Это класс ADO.NET. Его наследникам достаточно дать параметры с правильными именами (чем и занимается RFD, а правильные имена указываются с помощью MapField) и ADO.NET сама все распарсит и выполнит всю черновую работу. В общем RFD это оболчка над ADO.NET, более высокоуровневая, поэтому такими мелочами она не занисмается.
Не соглашусь. Классы, типа SqlCommand не заполняют параметры по строке запроса. Единственно, что они могут, создать параметры для хранимой процедуры через DeriveParameters
Здравствуйте, <Аноним>, Вы писали:
А>Не соглашусь. Классы, типа SqlCommand не заполняют параметры по строке запроса. Единственно, что они могут, создать параметры для хранимой процедуры через DeriveParameters
я в свою очередь приведу пример из MSDN
public void CreateMySqlCommand(SqlConnection myConnection,
string mySelectQuery, SqlParameter[] myParamArray) {
SqlCommand myCommand = new SqlCommand(mySelectQuery, myConnection);
myCommand.CommandText = "SELECT CustomerID, CompanyName FROM Customers WHERE Country = @Country AND City = @City";
myCommand.Parameters.Add(myParamArray);
for (int j=0; j<myParamArray.Length; j++)
{
myCommand.Parameters.Add(myParamArray[j]) ;
}
string myMessage = "";
for (int i = 0; i < myCommand.Parameters.Count; i++)
{
myMessage += myCommand.Parameters[i].ToString() + "\n";
}
MessageBox.Show(myMessage);
}
здесь можно увидеть наличие в строке запроса параметра (выделено жирным) и добавление значения этого параметра к экземпляру класса SqlCommand.
Хотя у меня начинает складываться впечатление, что мы говорим о разных вещах. Что вы имеете в виду под словами не заполняют параметры по строке запроса. Если вы считаете, что IDbCommand должны анализировать строку запроса и создавать параметры самостоятельно, то этого действительно нет. В RFD параметры создаются вручную или они создаются на основе бизнес-объекта с помощью функции CreateParameters (о чем уже неоднократно говорилось).
А вообще это пустой спор, за прошедшие сутки вы давно уже могли оттрассировать работу RFD и понять что там происходит.
Здравствуйте, <Аноним>, Вы писали:
А>Общего с вышеприведенным примером — метод CreateParameters. А как работает этот метод? Ведь, как известно, Reflection может возвращать свойства в любом порядке. Получается, что вместо RegionID может быть помещено Region.Description.
SQL Server использует именованные параметры, поэтому он положит всё куда надо. Параметры спокойно можно мешать и даже использовать один и тот же параметр в запросе несколько раз. Это фича сиквел сервера, с Access такой трюк не пройдёт, т.к. там параметры неименованные и задаются в виде '?'. В таких запросах должно быть чёткое следование параметров и метод CreateParameters для них скорее всего не подойдёт.
Сам метод работает очень просто — создаёт список параметров для всех мапируемых полей заданного объекта. Определение соответствия параметров производится только для сохранённых процедур. Подробнее узнать что собственно происходит можно подсмотрев в профайлере сформированные ADO.NET запросы.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Сам метод работает очень просто — создаёт список параметров для всех мапируемых полей заданного объекта. Определение соответствия параметров производится только для сохранённых процедур. Подробнее узнать что собственно происходит можно подсмотрев в профайлере сформированные ADO.NET запросы.
Не самый оптимальный способ. Например, для хранимой процедуры, принимающей три аргумента, заполнять массив аргументами по всем маппируемым полям, слишком расточительно. Почему бы не сделать проверку на предмет того, нужно значение данного поля у обекта или нет по названиям параметров?
Здравствуйте, mikа, Вы писали:
IT>>Сам метод работает очень просто — создаёт список параметров для всех мапируемых полей заданного объекта. Определение соответствия параметров производится только для сохранённых процедур. Подробнее узнать что собственно происходит можно подсмотрев в профайлере сформированные ADO.NET запросы.
M>Не самый оптимальный способ. Например, для хранимой процедуры, принимающей три аргумента, заполнять массив аргументами по всем маппируемым полям, слишком расточительно. Почему бы не сделать проверку на предмет того, нужно значение данного поля у обекта или нет по названиям параметров?
Главное что ты это понимаешь Если ты считаешь это слишком расточительным — используй другие способы, которые никто не отменял. Можно явно задать список необходимых параметров, для спроков можно использовать простую последовательность параметров, не создавая при этом сами объекты параметры. Но в случаях, когда мне нужно добавить новый объект в базу или сделать update существующему, то CreateParameters самое оно.
Если нам не помогут, то мы тоже никого не пощадим.