RFD Сохранение объектов. Как?
От: BVA Интернет  
Дата: 21.09.04 04:21
Оценка:
Уважаемые коллеги, начал разбираться с RFD и сразу столкнулся с проблемой.
Как читать объекты из БД — понятно, но к сожалению, не совсем понятно, как их туда правильно сохранять при помощи RFD.
Может кто покажет кусочек кода?
--
http://www.slideshare.net/vyacheslavbenedichuk
https://www.linkedin.com/in/vbenedichuk
Re: RFD Сохранение объектов. Как?
От: IT Россия linq2db.com
Дата: 22.09.04 13:27
Оценка:
Здравствуйте, 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.
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: RFD Сохранение объектов. Как?
От: SiAVoL Россия  
Дата: 22.09.04 13:47
Оценка:
Здравствуйте, IT, Вы писали:

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>

только вот вроде там если в хранимке были OUTPUT параметры то в объект они не попадали, я там руками подтачивал, помнится
... << RSDN@Home 1.1.4 beta 3 >>
Re[3]: RFD Сохранение объектов. Как?
От: IT Россия linq2db.com
Дата: 22.09.04 14:00
Оценка:
Здравствуйте, SiAVoL, Вы писали:

SAV>только вот вроде там если в хранимке были OUTPUT параметры то в объект они не попадали, я там руками подтачивал, помнится


Возможно А что именно подтачивал?
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: RFD Сохранение объектов. Как?
От: SiAVoL Россия  
Дата: 23.09.04 07:01
Оценка:
Здравствуйте, 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 void BackMapParametrs(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 как раз и осуществляет обратное отображение
... << RSDN@Home 1.1.4 beta 3 >>
Re[5]: RFD Сохранение объектов. Как?
От: IT Россия linq2db.com
Дата: 23.09.04 15:10
Оценка:
Здравствуйте, SiAVoL, Вы писали:

SAV>функция BackMapParametrs как раз и осуществляет обратное отображение


Там же есть методы InputOutputParameter и OutputParameter. Они разве не работают?
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: RFD Сохранение объектов. Как?
От: SiAVoL Россия  
Дата: 24.09.04 05:37
Оценка:
Здравствуйте, 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.
Re[3]: RFD Сохранение объектов. Как?
От: SiAVoL Россия  
Дата: 30.09.04 12:06
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>А как работает этот метод? Ведь, как известно, 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

Да, я тоже так подумал вначале. Но при детальном рассмотрении кода оказалось, что строка запроса нигде не разбирается.
Re[5]: RFD Сохранение объектов. Как?
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.10.04 09:24
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Да, я тоже так подумал вначале. Но при детальном рассмотрении кода оказалось, что строка запроса нигде не разбирается.

А зачем строку? Биндинг по именам спасает от неопределенности порядка.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: RFD Сохранение объектов. Как?
От: Аноним  
Дата: 01.10.04 09:35
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, <Аноним>, Вы писали:


А>>Да, я тоже так подумал вначале. Но при детальном рассмотрении кода оказалось, что строка запроса нигде не разбирается.

S>А зачем строку? Биндинг по именам спасает от неопределенности порядка.

А имена откуда получить можно? Только из строки запроса.
Re[7]: RFD Сохранение объектов. Как?
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.10.04 10:16
Оценка:
Здравствуйте, <Аноним>, Вы писали:
А>А имена откуда получить можно? Только из строки запроса.
А ты обратил внимание на атрибут 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)". Чтобы узнать соответствие параметров — значение следует выполнить сдедующие шаги:

  1. Из строки запроса получить название колонок (RegionID, RegionDescription)
  2. По названиям колонок через Reflection получить значения полей объекта Region
  3. Создать параметры IDbDataParameter

Первый шаг не выполняется
Re[5]: RFD Сохранение объектов. Как?
От: SiAVoL Россия  
Дата: 01.10.04 10:52
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Да, я тоже так подумал вначале. Но при детальном рассмотрении кода оказалось, что строка запроса нигде не разбирается.

просмотрите детально код еще раз и обратите внимание на использование интерфейса System.Data.IDbCommand. Это класс ADO.NET. Его наследникам достаточно дать параметры с правильными именами (чем и занимается RFD, а правильные имена указываются с помощью MapField) и ADO.NET сама все распарсит и выполнит всю черновую работу. В общем RFD это оболчка над ADO.NET, более высокоуровневая, поэтому такими мелочами она не занисмается.
... << RSDN@Home 1.1.4 beta 3 >>
Re[9]: RFD Сохранение объектов. Как?
От: SiAVoL Россия  
Дата: 01.10.04 10:56
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>

    А>
  1. Из строки запроса получить название колонок (RegionID, RegionDescription)
    делает ADO.NET

    А>
  2. По названиям колонок через Reflection получить значения полей объекта Region
    делает RFD

    А>
  3. Создать параметры IDbDataParameter
    можно сделать самому, можно отдать на откуп RFD
    А>

А>Первый шаг не выполняется

смотреть фунекцию CreateParameters и иже с нею
... << RSDN@Home 1.1.4 beta 3 >>
Re[9]: RFD Сохранение объектов. Как?
От: Alex Axyonov Украина  
Дата: 01.10.04 11:03
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

А>Здравствуйте, 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)". Чтобы узнать соответствие параметров — значение следует выполнить сдедующие шаги:


А>

    А>
  1. Из строки запроса получить название колонок (RegionID, RegionDescription)
    А>
  2. По названиям колонок через Reflection получить значения полей объекта Region
    А>
  3. Создать параметры 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
Re[7]: RFD Сохранение объектов. Как?
От: SiAVoL Россия  
Дата: 01.10.04 11:56
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Не соглашусь. Классы, типа 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 и понять что там происходит.
... << RSDN@Home 1.1.4 beta 3 >>
Re[3]: RFD Сохранение объектов. Как?
От: IT Россия linq2db.com
Дата: 03.10.04 05:16
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Общего с вышеприведенным примером — метод CreateParameters. А как работает этот метод? Ведь, как известно, Reflection может возвращать свойства в любом порядке. Получается, что вместо RegionID может быть помещено Region.Description.


SQL Server использует именованные параметры, поэтому он положит всё куда надо. Параметры спокойно можно мешать и даже использовать один и тот же параметр в запросе несколько раз. Это фича сиквел сервера, с Access такой трюк не пройдёт, т.к. там параметры неименованные и задаются в виде '?'. В таких запросах должно быть чёткое следование параметров и метод CreateParameters для них скорее всего не подойдёт.

Сам метод работает очень просто — создаёт список параметров для всех мапируемых полей заданного объекта. Определение соответствия параметров производится только для сохранённых процедур. Подробнее узнать что собственно происходит можно подсмотрев в профайлере сформированные ADO.NET запросы.
Если нам не помогут, то мы тоже никого не пощадим.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.