Еще вопросы к Toys\DataAccess
От: Дьяченко Александр Россия  
Дата: 17.10.05 23:36
Оценка:
Где и как можно вмешаться в создание обьекта (подсунуть вместо свеже созданого старый обьект)? А то интерфейсов много (IMapObjectFactory, IObjectFactory) а как этим воспользоваться не ясно...

Зарание спасибо.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Re: Еще вопросы к Toys\DataAccess
От: IT Россия linq2db.com
Дата: 18.10.05 00:49
Оценка: 9 (1)
Здравствуйте, Дьяченко Александр, Вы писали:

ДА>Где и как можно вмешаться в создание обьекта (подсунуть вместо свеже созданого старый обьект)? А то интерфейсов много (IMapObjectFactory, IObjectFactory) а как этим воспользоваться не ясно...


Отрывок из несостоявшейся статьи:

MapDescriptor

Класс MapDescriptor является ключевым звеном в реализации механизмов маппинга и фактически представляет собой в некотором смысле расширение технологии Reflection, предлагая высокопроизводительные альтернативы наиболее медленным её частям.

В конце статьи мы рассмотрим несколько тестов, позволяющих оценить производительность библиотеки. А пока подробнее остановимся на самом классе MapDescriptor.

Класс MapDescriptor создаётся для каждого типа, в момент первого обращения к методу Map.Descriptor. Каждый раз во время маппинга библиотечные функции получают дескриптор класса и используют его для создания объектов и доступа к их полям и свойствам. Для каждого типа библиотека генерирует специальную версию класса, перекрывая определённые виртуальные методы, что позволяет добиваться приемлемой производительности.

Для создания объектов используется семейство методов CreateInstance(Ex).

Если взглянуть на исходный код методов CreateInstance, то можно обнаружить там использование Reflection. Это реализация методов по умолчанию, которая перекрывается для каждого типа специально сгенерированной для этой цели функцией.

Методы CreateInstanceEx введены в библиотеку специально для того, чтобы получить возможность управлять созданием объектов во время маппинга. По умолчанию эти методы обращаются к методам CreateInstance, но мы можем перехватить управление и получить контроль над созданием объектов.

Предположим, у нас имеются следующие таблицы для хранения информации о пациентах и докторах.

CREATE TABLE dbo.Person (
    PersonID int NOT NULL PRIMARY KEY IDENTITY(1,1),
    Name     varchar(50)
) ON [PRIMARY]

CREATE TABLE dbo.Patient (
    PatientID int NOT NULL PRIMARY KEY,
    Birthday  datetime
) ON [PRIMARY]

CREATE TABLE Doctor (
    DoctorID int NOT NULL PRIMARY KEY,
    Taxonomy varchar(50)
) ON [PRIMARY]

Таблица Person содержит информацию, которая является общей как для пациентов, так и для докторов и в модели классов должна быть представлена базовым классом Person:

public class Person
{
  [MapField("PersonID")]
  public int    ID;
  public string Name;
}

public class Patient : Person
{
  public DateTime Birthday;
}

public class Doctor : Person
{
  public string Taxonomy;
}

Наша задача – научится создавать объект правильного типа в зависимости от того, к какому типу относиться запись в результирующем рекордсете.
Рассмотрим следующий пример:

class PersonObjectFactory : IMapObjectFactory
{
  public object CreateInstance(MapInitializingData data)
  {
    object o = 
      data.DataSource.GetFieldValue("PatientID", data.SourceData);

    if (!(o is DBNull))
    {
      data.MapDescriptor = Map.Descriptor(typeof(Patient));
      return data.MapDescriptor.CreateInstanceEx(data);
    }

    o = data.DataSource.GetFieldValue("DoctorID", data.SourceData);

    if (!(o is DBNull))
    {
      data.MapDescriptor = Map.Descriptor(typeof(Doctor));
      return data.MapDescriptor.CreateInstanceEx(data);
    }

    return Map.CreateInstance(typeof(Person));
  }
}

class Program
{
  static void Main(string[] args)
  {
    Map.Descriptor<Person>().ObjectFactory = new PersonObjectFactory();

    using (DbManager db = new DbManager())
    {
      List<Person> list = db
        .SetCommand(@"
          SELECT
            ps.*,
            pt.*,
            dt.*
          FROM
            Person ps
              LEFT JOIN Patient pt ON pt.PatientID = ps.PersonID
              LEFT JOIN Doctor  dt ON dt.DoctorID  = ps.PersonID")
        .ExecuteList<Person>();

      foreach (Person p in list)
      {
        Console.WriteLine("{0}", p.GetType().Name);

        MapDescriptor md = Map.Descriptor(p.GetType());

        foreach (IMemberMapper mm in md)
          Console.WriteLine("{0}: {1}", mm.Name, mm.GetValue(p));
      }
    }
  }
}

Если у нас имеется по одной записи в таблицах Patient и Doctor, то результат выполнения программы может быть следующим.

Patient
Birthday: 10/10/2000 12:00:00 AM
PersonID: 1
Name: Name 1

Doctor
Taxonomy: Physician
PersonID: 2
Name: Name 2

Класс PersonObjectFactory, использующийся в данном примере должен быть зарегистрирован как фабрика объектов где-нибудь в начале выполнения программы. После этого любой вызов CreateInstanceEx будет передавать управление методу CreateInstance интерфейса IMapObjectFactory. Обратите внимание на то, что если этот метод создаёт объект отличный от базового, то в параметре MapInitializingData переписывается поле MapDescriptor, для того чтобы обеспечить правильную работу маппинга нового объекта.

Фабрика объектов так же может быть полезна, если логика программы требует наличия всегда только одной копии конкретного объекта в памяти программы. В этом случае для уже существующих объектов метод IMapObjectFactory.CreateInstance может вернуть копию объекта из кеша.

Для доступа к источнику данных используется всё тот же параметр MapInitializingData. В принципе, вполне возможно реализовать свой механизм маппинга и установив свойство MapInitializingData.StopMapping в false сообщить библиотеке, что маппинг выполнять не нужно.

... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Еще вопросы к Toys\DataAccess
От: Дьяченко Александр Россия  
Дата: 18.10.05 05:31
Оценка:
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, Дьяченко Александр, Вы писали:


ДА>>Где и как можно вмешаться в создание обьекта (подсунуть вместо свеже созданого старый обьект)? А то интерфейсов много (IMapObjectFactory, IObjectFactory) а как этим воспользоваться не ясно...


[Покусано]

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


[Покусано]

Вот как раз как его зарегистрировать и не ясно. С остальным и по исходникам более или менее разобрался.

Судя по отрывку статья должна быть очень информативной. Вроде вопрос о том что бы ее куда-нибуть выложить подымался, но так ничего и не решили... А жаль... Может все таки куданить выложить то что есть?
Re[2]: Еще вопросы к Toys\DataAccess
От: IDL  
Дата: 18.10.05 08:46
Оценка:
Присоединяюсь, судя по отрывку статья должна быть очень интересной, содержательной и самое главное очень полезной. Было бы очень здорово если можно было ознакомится с ней.

Спасибо
Re[3]: Еще вопросы к Toys\DataAccess
От: IT Россия linq2db.com
Дата: 18.10.05 11:24
Оценка:
Здравствуйте, Дьяченко Александр, Вы писали:

ДА>Вот как раз как его зарегистрировать и не ясно. С остальным и по исходникам более или менее разобрался.


Можно попробовать в статическом конструкторе самого класса.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Еще вопросы к Toys\DataAccess
От: Andre Украина  
Дата: 18.10.05 18:55
Оценка:
ДА>>Где и как можно вмешаться в создание обьекта (подсунуть вместо свеже созданого старый обьект)? А то интерфейсов много (IMapObjectFactory, IObjectFactory) а как этим воспользоваться не ясно...

IT>Отрывок из несостоявшейся статьи:


А можно надеяться на публикацию статьи в следующих номерах RSDN Magazine?
... << RSDN@Home 1.1.4 beta 7 rev. 467>> :: silent
Я бы изменил мир — но Бог не даёт исходников...
Re[3]: Еще вопросы к Toys\DataAccess
От: IT Россия linq2db.com
Дата: 19.10.05 00:51
Оценка:
Здравствуйте, Andre, Вы писали:

A>А можно надеяться на публикацию статьи в следующих номерах RSDN Magazine?




Я сейчас усиленно занимаюсь новой версий RFD, где всё будет ещё круче так что даже не знаю, стоит ли пускать в журнал статью по версии, которая к выходу журнала уже будет не актуальна.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.