Здравствуйте, IT, Вы писали:
IT>Не надо сомневаться. Я вчера весь вечер убил, чтобы разрулить обратные ссылки. Сегодня буду переписывать всё на двойной проход по дереву, т.к. в один проход задача у меня не решилась. Там, конечно, не совсем просто маппинг, но задача схожая.
Ну вот для таких случаев можно вручную написать алгоритм, осуществляющий разруливание обратных ссылок. В принципе, для ЕМ можно написать конфигуратор, который будет это делать при этом не меняя самого ЕМ. Но эта задача встречается достаточно редко, чтобы из-за нее отказываться от реализации фичи полезной в 99% остальных случаев.
IT>В EM ты создаёшь маппер по типам источника и приёмника. Если в качестве источника будет не тип, который был при инициализации маппера, а его наследник, то всё будет пучком или возникнут проблемы?
Только что проверил — все работает нормально. Единственное что поля производного класса конечно никуда копироваться не будут, будут скопированы только поля базового. Если это критично, то можно просто не использовать заранее сгенерированный мэппер.
IT>А если моя логика подразумевает, что если в целевом объекте ссылка нулевая, то не нужно создавать по ней объекта?
Этот вариант использования мне раньше в голову не приходил, но можно добавить конфигурационный метод типа: FilterDestination(value => value != null)
Наверное, я так и сделаю.
IT>Маппер не должен хранить в себе состояние и не будет проблем.
Ага, сейчас так и сделано.
IT>Расти всегда есть куда. 25% это очень не плохо. Если раньше я только раздумывал, то теперь точно займусь этим для линка. Спасибо за проверку идеи
Кстати, что интересно, буст получается не только на value-типах (что ожидаемо), но даже на строках. Интересно, почему?
IT>Это чисто дизайнерские решения.
Верно, но оно очень популярно. Я с ним регулярно сталкиваюсь.
IT>>А если моя логика подразумевает, что если в целевом объекте ссылка нулевая, то не нужно создавать по ней объекта? T>Этот вариант использования мне раньше в голову не приходил, но можно добавить конфигурационный метод типа: FilterDestination(value => value != null) T>Наверное, я так и сделаю.
IT>>>Что делать в твоём примере, если в A есть обратная ссылка на Foo? Dog>>Нету ни циклических ни обратных... IT>А если завтра понадобится?
Завтра может понадобиться ещё не только это, но это совсем не повод не делать того что необходимо сейчас
IT>>>Можно, конечно, сделать. Но это уже будет совсем другой маппинг с другими правилами, больше похожий на клонирование. Dog>>Да. Вот что-то подобное надо. Dog>>... а что за другие правила ? Этих что есть хватает вроде, главное обойти и посоздавать всё акуратно. IT>Вот как раз что-то подобное клонированию сделать универсально не так просто.
А можно для начала хотя бы сделать не универсально ?
Здравствуйте, Dog, Вы писали:
IT>>Вот как раз что-то подобное клонированию сделать универсально не так просто. Dog>А можно для начала хотя бы сделать не универсально ?
Здравствуйте, Dog, Вы писали:
Dog>Не хочется устраивать из проекта зоопарк
С одной стороны да, но с другой задачи О2О сопоставления и ORM — это довольно разные задачи (что наглядно продемонстрировало это обсуждение) и нет ничего страшного в том, чтобы для решения разных задач применялись разные инструменты. Тем более, что у EmitMapper — это один проект (1 длл) без никаких зависимостей, не заставляет использовать никакие атрибуты, наследоваться ни от каких классов, не заставляет следовать никаким правилам и под неё не надо специально подстраиваться.
Здравствуйте, mrTwister, Вы писали:
T>Дак это проблемы BLT. Он другого интерфейса не предоставляет.
Дык BLT реализует интерфейсы или абстрактные классы BO сам, как же ты предварительно создашь неизвестный тип?
T>Плюс к этому BLT при конвертации value типов делает боксинг/анбоксинг. EM обходится без этого.
Да, и в конкретно нашем случае нам пришлось добавить пару сигнатур для ValueType, чтобы эффективно маппить массивы значений. В десяток-другой строк задача, но кроме меня, насколько я смотрю за BLT последние 5 лет, это никому не надо было.
К тому же в тесте ты свой маппер получил однократно, а BLT постоянно достаешь его из синхронизируемого контейнера, хотя мог бы постыпить точно так же. В общем, тест некорректен.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, mrTwister, Вы писали:
V>К тому же в тесте ты свой маппер получил однократно, а BLT постоянно достаешь его из синхронизируемого контейнера, хотя мог бы постыпить точно так же. В общем, тест некорректен.
Каким образом в BLT можно получить мэппер заранее, чтобы сделать также?
Ну, молодцы/молодец однозначно. При кол-ве пройденных тестов больше, чем NH, в среднем в 8-10 раз больше производительность на всех видах тестов. Без комментариев.
Здравствуйте, vdimas, Вы писали:
T>>Дак это проблемы BLT. Он другого интерфейса не предоставляет.
V>Дык BLT реализует интерфейсы или абстрактные классы BO сам, как же ты предварительно создашь неизвестный тип?
В случае О2О типы сопоставляемых объектов известны заранее практически всегда. В том 1% случаев, когда это не так, можно использовать интерфейс аналогичный БЛТ и даже тогда ЕМ все равно быстрее. В этой теме было заявлено, что БЛТ — это полноценный О2О мэппер, вот и тестировать его тогда надо согласно вариантам использования О2О мэпперов.
Далее, учитывая, что БЛТ на порядок проще и беднее, чем ЕМ (как О2О мэппер) сравнивать их производительность также не совсем корректно. Например, если бы БЛТ был полноценным мэппером, мне было бы интересно посмотреть на его производительность в сложных случаях типа вложенной nullable структуры, которая доступна через свойство. Или кастомных конверторов/конструкторов. В ЕМ учитывается огромное количество всяких хитрых таких вариантов, причем делается это максимально эффективным способом, как если бы это делал человек кодировал вручную. Ничего этого нет в БЛТ именно по причине того, что он примитивен как О2О мэппер.
T>>Плюс к этому BLT при конвертации value типов делает боксинг/анбоксинг. EM обходится без этого.
V>Да, и в конкретно нашем случае нам пришлось добавить пару сигнатур для ValueType, чтобы эффективно маппить массивы значений.
В EmitMapper по умолчанию доступно 679 типизированных сигнатур для ValueType, плюс пользователь может сам добавлять кастомные конверторы для любых типов которые также будут работать без боксинга/анбоксинга:
public class A
{
public string fld1;
public string fld2;
}
public class B
{
public int fld1 = 1;
public int fld2 = 2;
}
[TestMethod]
public void Test_CustomConverter2()
{
A a = Context.objMan.GetMapper<B, A>(
new DefaultMapConfig().ConvertUsing<int, string>(v => "converted " + v.ToString())
).Map(new B());
Assert.AreEqual("converted 1", a.fld1);
Assert.AreEqual("converted 2", a.fld2);
}
V>насколько я смотрю за BLT последние 5 лет, это никому не надо было.
А как ты это определил? 99% либо забивают на производительность, либо переписывают код вручную.
Здравствуйте, mrTwister, Вы писали:
T>Здравствуйте, AndrewVK, Вы писали:
AVK>>А это вовсе не вопрос, потому что проблемы с конкретной удочкой вполне решаемы написанием собственной удочки в крайнем случае.
T>Прекрасно. Сколько надо написать кода для маппинга вложенных структур (в том числе рекурсивных)?
ленно по вечерам — недельку.
рекурсивных эт Parent.Child.Parent object.ReferenceEquals(Parent, Parent.Child.Parent)?
BLT вообще дает возможность мапить чего угодно на чего угодно. То что поставляется штатно, это наиболее часто используемая вещь.
Здравствуйте, ili, Вы писали:
ili>ленно по вечерам — недельку.
Это кажется, что легко. Если серьезно подходить к задаче, то окажется, что там много противных нюансов. Например, маппинг в структуры (которые могут быть доступны через свойства), коллекции, отсутствие default-конструкторов, копирование по ссылке или по значению и т.д.
ili>рекурсивных эт Parent.Child.Parent object.ReferenceEquals(Parent, Parent.Child.Parent)?
Да
Здравствуйте, mrTwister, Вы писали:
T>Это кажется, что легко. Если серьезно подходить к задаче, то окажется, что там много противных нюансов. Например, маппинг в структуры (которые могут быть доступны через свойства), коллекции, отсутствие default-конструкторов, копирование по ссылке или по значению и т.д.
вот про отсутствие дефолтных конструкторов, я, честно признаться не подумал, ну еще день.
имхо, О2О, это скорее вопрос одного конкретного случая, и под конкретные правила BLT очень хорошо решает задачи (задавать правила и в рамках них решать задачу там достаточно просто, и это при учете знания библиотеки немногим выше уровня, описанного в вики). половина тех нюансов что ты отметил этими конкретными правилами просто отметется.
а время на работы, соответственно, еще уменьшится.
вот в этом-то и есть вся сила BLT.
(эт я тут не религию распространяю, эт я опытом делюсь под конкретно заданый вопрос, если что)
ili>>рекурсивных эт Parent.Child.Parent object.ReferenceEquals(Parent, Parent.Child.Parent)? T>Да
вот это, пожалуй самый гнусный момент если в эмит.маппере он сделан, то скажи куда глянуть, было бы интересно перенять опыт
Здравствуйте, ili, Вы писали:
ili>вот про отсутствие дефолтных конструкторов, я, честно признаться не подумал, ну еще день.
ili>имхо, О2О, это скорее вопрос одного конкретного случая, и под конкретные правила BLT очень хорошо решает задачи (задавать правила и в рамках них решать задачу там достаточно просто, и это при учете знания библиотеки немногим выше уровня, описанного в вики). половина тех нюансов что ты отметил этими конкретными правилами просто отметется. ili>а время на работы, соответственно, еще уменьшится. ili>вот в этом-то и есть вся сила BLT. ili>(эт я тут не религию распространяю, эт я опытом делюсь под конкретно заданый вопрос, если что)
Ок, чтобы сделать разговор более предметным, не мог бы ты продемонстрировать этот код. Когда меня спросили про атрибуты для мэппинга я показал несколько строк кода, которые их реализуют. Давай сделаем также?
ili>>>рекурсивных эт Parent.Child.Parent object.ReferenceEquals(Parent, Parent.Child.Parent)? T>>Да
ili>вот это, пожалуй самый гнусный момент если в эмит.маппере он сделан, то скажи куда глянуть, было бы интересно перенять опыт
Эта задача решается через построение графа объектов и это можно сделать через кастомную конфигурацию к EM. По-умолчанию ЕМ граф не строит, но если хочешь, я могу вечером накидать несколько строк кода, которые показывают, как это сделать с помощью ЕМ.
Вообще, я немного потерял контекст обсуждения, выше я имел ввиду рекурсивные структуры данных типа списка. То есть когда структура данных циклическая, а граф нециклический.
ili>вот про отсутствие дефолтных конструкторов, я, честно признаться не подумал, ну еще день.
тебе понадобилось 20 минут для того чтоб маппинг на record F# заработал
хотя при o2o сложностей наверняка больше: вложенность, циклические связки и т.д.
Из практических вещей для меня Emit мог бы пригодится например возможностью мапить model на view в MVC.
например есть два-три объекта которые являются моделью в контроллере, нужно взять пару свойств из одного и другого,
и замапить на объект который будет использоваться для view.
Здравствуйте, mrTwister, Вы писали:
T>Ок, чтобы сделать разговор более предметным, не мог бы ты продемонстрировать этот код. Когда меня спросили про атрибуты для мэппинга я показал несколько строк кода, которые их реализуют. Давай сделаем также?
давай только это не пара строк кода скажем, я могу сказать куда смотреть (наследование от ObjectMapper, возможно с добавлением MetaDataProvider)
если интересен именно код, то нарисуй тест, который BLT валит, а я приведу его в рабочее состояние (сразу скажу приводить буду "ленно", просто естт джоб, который сейчас надо делать, а вечером спать охота очень )
только пожелей меня чутка, обойдемся без циклических ссылок по object.ReferenceEquals(Parent, Parent.Child.Parent) и ограничимся наличием дефолтных конструкторов.
ili>>>>рекурсивных эт Parent.Child.Parent object.ReferenceEquals(Parent, Parent.Child.Parent)? T>>>Да
ili>>вот это, пожалуй самый гнусный момент если в эмит.маппере он сделан, то скажи куда глянуть, было бы интересно перенять опыт
T>Эта задача решается через построение графа объектов и это можно сделать через кастомную конфигурацию к EM. По-умолчанию ЕМ граф не строит, но если хочешь, я могу вечером накидать несколько строк кода, которые показывают, как это сделать с помощью ЕМ.
было бы интересно, если не затруднит.
T>Вообще, я немного потерял контекст обсуждения, выше я имел ввиду рекурсивные структуры данных типа списка. То есть когда структура данных циклическая, а граф нециклический.
эээ... при этих словах я почувствовал себя полным ничтожеством рядом с гигантом мысли переведи, пожалуйста =)
Здравствуйте, cadet354, Вы писали:
C>Здравствуйте, ili, Вы писали:
ili>>вот про отсутствие дефолтных конструкторов, я, честно признаться не подумал, ну еще день. C>тебе понадобилось 20 минут для того чтоб маппинг на record F# заработал
эмн... там какраз был в наличии вполне конкретный случай. как я и говорил, конкретику BLT решает хорошо и быстро.
бишь то, что я нарисовал для record годится только для него и только при условии что имена параметров конструктора совпадают с именами полей.
ili>эмн... там какраз был в наличии вполне конкретный случай. как я и говорил, конкретику BLT решает хорошо и быстро. ili>бишь то, что я нарисовал для record годится только для него и только при условии что имена параметров конструктора совпадают с именами полей.
Думаю прикрутить чтение имена параметров из атрибутов не займет много времени.
Здравствуйте, mrTwister, Вы писали:
T>http://emitmapper.codeplex.com
T>Emit Mapper — это мощная легковесная библиотека для проецирования одних объектов на другие. Имеет следующие особенности:
Можно ли портировать под .NET 2.0?
Я посмотрел, из 3.5 там используется только System.Core. Для net2.0 ее вполне можно заменить на LinqBridge. Там есть реализации Enumerable, Func<> и Action<> и определен ExtensionAttribute, единственное из необходимого твоему мапперу, чего там нет — это класса HashSet, но его можно заменить на HashTable.