IMapGettable хочется
От: oleksab Украина  
Дата: 08.11.05 08:49
Оценка:
Добрый день


Есть классы, которые содержат в себе ссылки на объекты других классов, что-то типа:
 class Classificator
 {
 int id;
 string Title;
 }

 class SomeObject
 {
 int id;
 string Title;
 Classificator Type;
 }


Загружать объекты в таком случае помогает реализация IMapSettable классом SomeObject
Хочется, чтобы при сохранении объектов (при создании параметров с помощью DbManager.CreateParameters(object source)) можно было также обойтись реализацией IMapGettable, в которой можно было бы переопределить метод GetField и внутри него можно было написать:
        public bool GetField(string fieldName, out object value)
        {
            MapDescriptor md = MapDescriptor.GetDescriptor(this.GetType());
            IMemberMapper mapper = md.GetMember(fieldName);
            if (mapper != null && mapper.IsClass && mapper.MemberType.IsSubclassOf(typeof (Classificator)))
            {
                Classificator c = mapper.GetValue(this);
                value = c.id;
                return true;
            }
            return false;
        }


Скажите пожалуйста, реализовано что-то подобное?
Может можно как-то по-другому? Подскажите пожалуйста, как?
Каковы шансы того, что если я напишу этот самый IMpaGettable, переделаю все места, где встречается IMapDataSource.GetFieldData и отдам автору исходники, подобный код попадет в основную ветку (а то merge-ить при новой версии не очень улыбается)?

Спасибо.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re: IMapGettable хочется
От: oleksab Украина  
Дата: 08.11.05 16:56
Оценка:
Здравствуйте, oleksab, Вы писали:

Достаточно ли будет переписать в MapDescriptor методы GetFieldValue?
        object IMapDataSource.GetFieldValue(int i, object entity)
        {
            IMemberMapper mm = (IMemberMapper)_memberList[i];
            
            IMapGettable mg;
            if ((mg = entity as IMapGettable) != null)
            {
                object value;
                if (mg.GetField((this as IMapDataSource).GetFieldName(i), out value))
                    return value;
            }
            return mm.GetValue(entity);
        }

        object IMapDataSource.GetFieldValue(string name, object entity)
        {
            IMemberMapper mm = this[name];

            IMapGettable mg;
            if ((mg = entity as IMapGettable) != null)
            {
                // TODO : should mm be tested for null ?
                object value;
                if (mg.GetField(name, out value))
                    return value;
            }
            return mm != null ? mm.GetValue(entity) : null;
        }

и добавить
    public interface IMapGettable
    {
        bool GetField(string fieldName, out object value);
    }

?

Неудобно только то, что всем out параметрам нужно будет явно присваивать значение в реализации GetFieldstring fieldName, out object value).
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re[2]: IMapGettable хочется
От: IT Россия linq2db.com
Дата: 09.11.05 02:05
Оценка:
Здравствуйте, oleksab, Вы писали:

O> Неудобно только то, что всем out параметрам нужно будет явно присваивать значение в реализации GetFieldstring fieldName, out object value).


Да уж, как-то это всё не очень... Я бы глянул в сторону конструктора с MapInitializeData параметром. Он перед маппингом получает в это структуре все необходимые данные.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[3]: IMapGettable хочется
От: oleksab Украина  
Дата: 09.11.05 08:14
Оценка:
Здравствуйте, IT, Вы писали:

O>> Неудобно только то, что всем out параметрам нужно будет явно присваивать значение в реализации GetFieldstring fieldName, out object value).


IT>Да уж, как-то это всё не очень...


Не очень out? Его можно поменять на ref
Или сама идея вызывать IMapGettable.GetField в MapDescriptor.GetFieldValue плоха?
Можно переделать с ref как
        object IMapDataSource.GetFieldValue(string name, object entity)
        {
            IMemberMapper mm = this[name];

            object value = mm != null ? mm.GetValue(entity) : null;
            IMapGettable mg;
            if ((mg = entity as IMapGettable) != null && value != null)
            {
                mg.GetField(name, ref value);
            }
            return value;
        }

Тогда IMapGettable.GetField если захочет — изменит значение value. Ну а если нет — то нет.

IT>Я бы глянул в сторону конструктора с MapInitializeData параметром. Он перед маппингом получает в это структуре все необходимые данные.


Это в смысле Map.MapInternal? Но там проверку на реализацию IMapGettable прийдется делать в двух местах:

        Map.MapInternal(
                IMapDataSource   source,
                object           sourceData,
                IMapDataReceiver receiver,
                object           receiverData,
                MapInitializingData data)
        {
            if (receiverData is ISupportInitialize)
                ((ISupportInitialize)receiverData).BeginInit();
            // реализует ли sourceData IMapGettable
            IMapGettable mg = sourceData as IMapGettable;
            
            if (receiverData is IMapSettable)
            {
                IMapSettable mapReceiver = (IMapSettable)receiverData;

                for (int i = 0; i < source.FieldCount; i++)
                {
                    string name = source.GetFieldName(i);
                    object o    = source.GetFieldValue(i, sourceData);
                    // проверка №1 
                    if (mg != null)
                    {
                        // скажем для какого поля будет подставлено значение
                        mg.GetField(name, ref o);
                    }

                    MapDescriptor md = data.MapDescriptor;
                
                    if (mapReceiver.SetField(name, o) == false)
                    {
                        int idx = receiver.GetOrdinal(name);

                        if (idx >= 0)
                        {
                            receiver.SetFieldValue(idx, name, receiverData, o);
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < source.FieldCount; i++)
                {
                    string name = source.GetFieldName(i);

                    // -----------------------------------
                    if (name.Length > 0)
                    {
                        int idx  = receiver.GetOrdinal(name);

                        if (idx >= 0)
                        {
                            object o = source.GetFieldValue(i, sourceData);
                            // проверка №2
                            if (mg != null)
                            {
                                // скажем для какого поля будет подставлено значение
                                mg.GetField(name, ref o);
                            }
                            receiver.SetFieldValue(idx, name, receiverData, o);
                        }
                    }
                }
            }

            if (receiverData is ISupportInitialize)
                ((ISupportInitialize)receiverData).EndInit();
        }
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re[4]: IMapGettable хочется
От: oleksab Украина  
Дата: 09.11.05 09:05
Оценка:
Я в предидущем посте налажал и тело взял не от того MapInternal:
        internal static void MapInternal(
            IMapDataSource source,
            object sourceData,
            IMapDataReceiver receiver,
            object receiverData)
        {
            if (receiverData is ISupportInitialize)
                ((ISupportInitialize)receiverData).BeginInit();

            IMapGettable mg = sourceData as IMapGettable;

            if (receiverData is IMapSettable)
            {
                IMapSettable mapReceiver = (IMapSettable)receiverData;

                for (int i = 0; i < source.FieldCount; i++)
                {
                    string name = source.GetFieldName(i);
                    object o = source.GetFieldValue(i, sourceData);
                    if (mg != null)
                    {
                        mg.GetField(name, ref o);
                    }

                    if (mapReceiver.SetField(name, o) == false)
                    {
                        int idx = receiver.GetOrdinal(name);

                        if (idx >= 0)
                        {
                            receiver.SetFieldValue(idx, name, receiverData, o);
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < source.FieldCount; i++)
                {
                    string name = source.GetFieldName(i);

                    // -----------------------------------
                    if (name.Length > 0)
                    {
                        int idx = receiver.GetOrdinal(name);

                        if (idx >= 0)
                        {
                            object o = source.GetFieldValue(i, sourceData);
                            if (mg != null)
                            {
                                mg.GetField(name, ref o);
                            }

                            receiver.SetFieldValue(idx, name, receiverData, o);
                        }
                    }
                }
            }

            if (receiverData is ISupportInitialize)
                ((ISupportInitialize)receiverData).EndInit();
        }
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.