Возникла следующая задача есть типовой метод для сохранения Document и Attachment в нескольких контроллерах, было выбранно решение использовать Патерн Service Layout,что бы метод сохраниения вызывался с одного места,как известно весь код в apex если говорить про бест рractice должен быть bulkificaiton то есть работать с пачками данных,в документации приводится пример что методы Service Layout принимают враппер класс где есть два значения Id и Sobject.В моем случае нету ID. В связи с этим возник вопрос как должны быть связанны document и attachment в бест practice,пролема в том что в теории метод может быть вызван сразу с нескольких мест и возможно будет обрабатываться пачка
Вариант
public static void insertDocumentAndAttachment(List<map<Document,Attachment>> mapDocumentAttachments)
мне не очень нравится потому что в качестве ключа используется Sobject
Если не много по размыслить можно найти решение типо List<map<String,wrapperclassDocumentAttachment>>
где стриг в мапе имя контроллера и возможно какое то рандомное значение.
Либо я все очень сильно усложняю и можно использовать решение по проще?.
все решил что я туплю видать за работался
можно прост враппер использовать.
Вот так map<Document,Attachment> лучше не надо, класть SObject в ключ хеш таблицы это не очень хорошая идея, потому как в Apex получение хешкода из SObject никак не контролируется.
Зачем тебе Map вообще?
Используй просто SObject[], где будут Document и Attachment.
Это в смысле нельзя изменить порядок расчета хешкода или есть проблемы с этими самыми хешкодами?
Или DTO
class MegaObjectDocumentAttachmentDTO {
public sObject object;
public Document document;
public Attachment attachment;
}Ну как мы с вами понимаем Apex на самом деле выполняется поверх Java, следовательно у всех объектов есть метод hashCode(), который непременно вызывается для ключа при покладании чего-ли в ассициативный массив (потому как Map в Apex это HashMap). Переопределить его (т.е. hashCode()) для SObject нельзя (как и наследовать от SObject, откуда растут ноги всех этих wrapper паттернов). Таким образом:
Account a = new Account(Name = 'TestAccount'); // create key
Map<Account, Integer> m = new Map <Account, Integer>();
m.put(a, 0); // put to the map
System.assert(m.containsKey(a) == true); // check, all is ok
a.Name = 'TestAccount1'; // change the key
System.assert(m.containsKey(a) == true); // oooops, it fails
Прикольно, я думал что в качестве хешкода используется адрес в памяти.
А так согласен странно что хэш меняется при изменении самих полей.
По идее такое поведение должно быть кастомным (если я правильно помню из java)
Не совсем корректно.
Я бы сказал, выполняется на JVM.
А что вы скажете по поводу вот этого?
https://www.salesforce.com/us/developer/docs/dbcom_apex290/Content/langCon_apex_collections_maps_keys_userdefined.htm
When using a custom type (your Apex class) for the map key or set elements, provide equals and hashCode methods in your class. Apex uses these two methods to determine equality and uniqueness of keys for your objects.
А млин, это по ходу для классов, а не для объектов.
Хотя объект можно обернуть в класс DTO и приделать к нему кастомный hashCode()
Все правильно, но это для ваших классов, а не для SObject
Вот я и пишу, что отсюда растут ноги всяких wrapper'ов.
Зачем вообще объект использовать в роли ключа?
просто обсудили возможность. Понятное дело никто так не делает.
Проще придумать какой-нибудь ключ (любой сложности, составной) в виде String.
У меня как-то была такая задача, не помню как я к такому пришел, но у меня была стандартная мапа <Id, sObject>
Но по логике туда нужно было добавлять новые объекты, которые конечно не содержат Id.
Делал очень просто - поменял на Map<String, sObject>, и если объект содержал Id, то в ключ попадал его Id, а если была новая запись то я в качестве ключа делал - "000"+UUID (000 нужен был чтобы далее определить что ID фейковый, а UUID чтобы ключ мапы получился псевдо-уникальный)
Понятно что не элегантное решение, но это потребовало минимум изменений в существующем функционале.
Кстати вопрос к тем кто имел опыт работы с java.
Как часто вы переназначали equals() и hascode() в реальных проектах на java?
Помню сколько готовился к java собеседованиям и пробовал проходить их это был второй вопрос после понятий ООП.
Хотя интересовался у своих знакомых java разработчиков, никто и никогда это дело в проектах не использует. И более того один мне сказал что это зло переназначать эти функции, потому что во первых есть большая вероятность накосячить с правилами (по неосторожности) а во вторых это засада для других программистов если они не будут знать про то что данные методы переназначены.
Много раз делали. Собственно, эти методы естественно появляются в процессе разработки и этот топик отличный тому пример: надо работать с некой сущностью, под нее делают класс, рано или поздно этот класс нужно будет положить в Map (который в 90% случаем HashMap), ну например чтобы считать количество этих объектов поступающих откуда нибудь. Вот и надо приходится определять hashCode(), он тянет за собой equals() и завертелось ...
вот что типо такого было сделанно,интересно что сразу нашел решение после того как запостил на форум.Так объяснил что сам понял;) Дена апльмана в книги была даже целая глава почему нельзя использовать SObject в качестве ключа.
[quote="Dmitry Shnyrev"][quote="Gres"]Используй просто SObject[], где будут Document и Attachment.[/quote]
Или DTO
[code]
class MegaObjectDocumentAttachmentDTO {
public sObject object;
public Document document;
public Attachment attachment;
}
[/code]
ну или какие-нибудь варианты в зависимости от задачи :)[/quote]
вот что типо такого было сделанно,интересно что сразу нашел решение после того как запостил на форум.Так объяснил что сам понял;) Дена апльмана в книги была даже целая глава почему нельзя использовать SObject в качестве ключа.