Регистрация  |  Вход

Патерн Service Layout

Возникла следующая задача есть типовой метод для сохранения 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>>
где стриг в мапе имя контроллера и возможно какое то рандомное значение.

Либо я все очень сильно усложняю и можно использовать решение по проще?.

Возникла следующая задача есть типовой метод для сохранения 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 никак не контролируется.

Вот так [b]map<Document,Attachment>[/b] лучше не надо, класть SObject в ключ хеш таблицы это не очень хорошая идея, потому как в Apex получение хешкода из SObject никак не контролируется.

Зачем тебе Map вообще?
Используй просто SObject[], где будут Document и Attachment.

Зачем тебе Map вообще?
Используй просто SObject[], где будут Document и Attachment.

Mike V
в Apex получение хешкода из SObject никак не контролируется

Это в смысле нельзя изменить порядок расчета хешкода или есть проблемы с этими самыми хешкодами?

[quote="Mike V"]в Apex получение хешкода из SObject никак не контролируется[/quote]
Это в смысле нельзя изменить порядок расчета хешкода или есть проблемы с этими самыми хешкодами?

Gres
Используй просто SObject[], где будут Document и Attachment.

Или DTO
class MegaObjectDocumentAttachmentDTO {
public sObject object;
public Document document;
public Attachment attachment;
}

ну или какие-нибудь варианты в зависимости от задачи

[quote="Gres"]Используй просто SObject[], где будут Document и Attachment.[/quote]
Или DTO
[code]
class MegaObjectDocumentAttachmentDTO {
    public sObject object;
    public Document document;
    public Attachment attachment;
}
[/code]
ну или какие-нибудь варианты в зависимости от задачи :) 

Dmitry Shnyrev
Mike V
в Apex получение хешкода из SObject никак не контролируется

Это в смысле нельзя изменить порядок расчета хешкода или есть проблемы с этими самыми хешкодами?

Ну как мы с вами понимаем 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

Поскольку мы не контролируем hashCode() любое изменение ключа может сломать поиск в ассоциативном массиве. Более того, мы не знаем как реализован hashCode (а скорее всего там свертка хешей по каким-то полям) поэтому оно поведет вообще непредсказуемо. Ключи в виде примитивных типов лишены этой проблемы, поскольку передаются по значению. В принципе, никто не мешает иметь в виде ключа пользовательский тип данных, но тогда нужно помнить о согласованности hashCode и equals (ну это впрочем как в Java, C#, etc)

[quote="Dmitry Shnyrev"][quote="Mike V"]в Apex получение хешкода из SObject никак не контролируется[/quote]
Это в смысле нельзя изменить порядок расчета хешкода или есть проблемы с этими самыми хешкодами?[/quote]

Ну как мы с вами понимаем Apex на самом деле выполняется поверх Java, следовательно у всех объектов есть метод hashCode(), который непременно вызывается для ключа при покладании чего-ли в ассициативный массив (потому как Map в Apex это HashMap). Переопределить его (т.е. hashCode()) для SObject нельзя (как и наследовать от SObject, откуда растут ноги всех этих wrapper паттернов). Таким образом:
[code]
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
[/code]
Поскольку мы не контролируем hashCode() [b]любое[/b] изменение ключа может сломать поиск в ассоциативном массиве. Более того, мы не знаем как реализован hashCode (а скорее всего там свертка хешей по каким-то полям) поэтому оно поведет вообще непредсказуемо. Ключи в виде примитивных типов лишены этой проблемы, поскольку передаются по значению. В принципе, никто не мешает иметь в виде ключа пользовательский тип данных, но тогда нужно помнить о согласованности hashCode и equals (ну это впрочем как в Java, C#, etc)

Прикольно, я думал что в качестве хешкода используется адрес в памяти.
А так согласен странно что хэш меняется при изменении самих полей.
По идее такое поведение должно быть кастомным (если я правильно помню из java)

Прикольно, я думал что в качестве хешкода используется адрес в памяти. 
А так согласен странно что хэш меняется при изменении самих полей.
По идее такое поведение должно быть кастомным (если я правильно помню из java)

Mike V
Ну как мы с вами понимаем Apex на самом деле выполняется поверх Java

Не совсем корректно.
Я бы сказал, выполняется на JVM.

[quote="Mike V"]Ну как мы с вами понимаем Apex на самом деле выполняется поверх Java[/quote]
Не совсем корректно.
Я бы сказал, выполняется на 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.

А что вы скажете по поводу вот этого?
https://www.salesforce.com/us/developer/docs/dbcom_apex290/Content/langCon_apex_collections_maps_keys_userdefined.htm

[i]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.[/i]

А млин, это по ходу для классов, а не для объектов.
Хотя объект можно обернуть в класс DTO и приделать к нему кастомный hashCode()

А млин, это по ходу для классов, а не для объектов.
Хотя объект можно обернуть в класс DTO и приделать к нему кастомный hashCode()

Все правильно, но это для ваших классов, а не для SObject

Все правильно, но это для ваших классов, а не для SObject

Dmitry Shnyrev
А млин, это по ходу для классов, а не для объектов.
Хотя объект можно обернуть в класс DTO и приделать к нему кастомный hashCode()

Вот я и пишу, что отсюда растут ноги всяких wrapper'ов.

[quote="Dmitry Shnyrev"]А млин, это по ходу для классов, а не для объектов.
Хотя объект можно обернуть в класс DTO и приделать к нему кастомный hashCode()[/quote]

Вот я и пишу, что отсюда растут ноги всяких wrapper'ов.

Зачем вообще объект использовать в роли ключа?

Зачем вообще объект использовать в роли ключа?

Gres
Зачем вообще объект использовать в роли ключа?

просто обсудили возможность. Понятное дело никто так не делает.
Проще придумать какой-нибудь ключ (любой сложности, составной) в виде String.

[quote="Gres"]Зачем вообще объект использовать в роли ключа?[/quote]
просто обсудили возможность. Понятное дело никто так не делает.
Проще придумать какой-нибудь ключ (любой сложности, составной) в виде String.

У меня как-то была такая задача, не помню как я к такому пришел, но у меня была стандартная мапа <Id, sObject>
Но по логике туда нужно было добавлять новые объекты, которые конечно не содержат Id.
Делал очень просто - поменял на Map<String, sObject>, и если объект содержал Id, то в ключ попадал его Id, а если была новая запись то я в качестве ключа делал - "000"+UUID (000 нужен был чтобы далее определить что ID фейковый, а UUID чтобы ключ мапы получился псевдо-уникальный)
Понятно что не элегантное решение, но это потребовало минимум изменений в существующем функционале.

У меня как-то была такая задача, не помню как я к такому пришел, но у меня была стандартная мапа <Id, sObject>
Но по логике туда нужно было добавлять новые объекты, которые конечно не содержат Id. 
Делал очень просто - поменял на Map<String, sObject>, и если объект содержал Id, то в ключ попадал его Id, а если была новая запись то я в качестве ключа делал - "000"+UUID (000 нужен был чтобы далее определить что ID фейковый, а UUID чтобы ключ мапы получился псевдо-уникальный)
Понятно что не элегантное решение, но это потребовало минимум изменений в существующем функционале.

Кстати вопрос к тем кто имел опыт работы с java.
Как часто вы переназначали equals() и hascode() в реальных проектах на java?
Помню сколько готовился к java собеседованиям и пробовал проходить их это был второй вопрос после понятий ООП.
Хотя интересовался у своих знакомых java разработчиков, никто и никогда это дело в проектах не использует. И более того один мне сказал что это зло переназначать эти функции, потому что во первых есть большая вероятность накосячить с правилами (по неосторожности) а во вторых это засада для других программистов если они не будут знать про то что данные методы переназначены.

Кстати вопрос к тем кто имел опыт работы с java.
[b]Как часто вы переназначали equals() и hascode() в реальных проектах на java?[/b]
Помню сколько готовился к java собеседованиям и пробовал проходить их это был второй вопрос после понятий ООП.
Хотя интересовался у своих знакомых java разработчиков, никто и никогда это дело в проектах не использует. И более того один мне сказал что это зло переназначать эти функции, потому что во первых есть большая вероятность накосячить с правилами (по неосторожности) а во вторых это засада для других программистов если они не будут знать про то что данные методы переназначены.

Много раз делали. Собственно, эти методы естественно появляются в процессе разработки и этот топик отличный тому пример: надо работать с некой сущностью, под нее делают класс, рано или поздно этот класс нужно будет положить в Map (который в 90% случаем HashMap), ну например чтобы считать количество этих объектов поступающих откуда нибудь. Вот и надо приходится определять hashCode(), он тянет за собой equals() и завертелось ...

Много раз делали. Собственно, эти методы естественно появляются в процессе разработки и этот топик отличный тому пример: надо работать с некой сущностью, под нее делают класс, рано или поздно этот класс нужно будет положить в Map (который в 90% случаем HashMap), ну например чтобы считать количество этих объектов поступающих откуда нибудь. Вот и надо приходится определять hashCode(), он тянет за собой equals() и завертелось ...

Dmitry Shnyrev
Gres
Используй просто SObject[], где будут Document и Attachment.

Или DTO
class MegaObjectDocumentAttachmentDTO {
public sObject object;
public Document document;
public Attachment attachment;
}

ну или какие-нибудь варианты в зависимости от задачи :)

вот что типо такого было сделанно,интересно что сразу нашел решение после того как запостил на форум.Так объяснил что сам понял;) Дена апльмана в книги была даже целая глава почему нельзя использовать 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 в качестве ключа.