Я пытаюсь написать общий метод, который с любым именем сущности Dynamics 365 и набором идентификаторов (GUIDS) будет отвечать набором записей сущностей, соответствующих этому перечисляемому набору. Я разочарован тем, что не представляется эффективным способом заставить API просто использовать «первичный ключ идентификатора», не получая его сначала из метаданных, другого (казалось бы, ненужного) приема в оба конца.
Рассмотрим следующий (взломанный) метод:
public EntityCollection HackedFetchEntityRecordsById(IOrganizationService orgSvc, string entityName, IEnumerable<Guid> primaryEntityAttributeIds)
{
// Defacto HACK for getting primary entity attribute
string primaryEntityAttribute = $"{entityName}id";
StringBuilder sb = new StringBuilder();
foreach (Guid guid in primaryEntityAttributeIds)
{
sb.AppendLine($@"<value>{guid}</value>");
}
string fetchXml = $@"
<fetch mapping='logical'>
<entity name='{entityName}'>
<no-attrs />
<filter>
<condition attribute='{primaryEntityAttribute}' operator='in'>
{sb}
</condition>
</filter>
</entity>
</fetch> ";
return orgSvc.RetrieveMultiple(new FetchExpression(fetchXml));
}
Обратите внимание, что здесь я просто использую стандарт де-факто, который я наблюдал, поскольку кажется, что Microsoft решила назвать первичные атрибуты id для сущностей с именем сущности, за которым следует строка «id». Это явно небезопасный и ужасный способ сделать это.
Я могу сделать это "правильным" способом, но это неэффективно:
public EntityCollection InefficientFetchEntityRecordsById(IOrganizationService orgSvc, string entityName, IEnumerable<Guid> primaryEntityAttributeIds)
{
// "Correct" but inefficient way of getting primary entity attribute
string primaryEntityAttribute = ((RetrieveEntityResponse) orgSvc.Execute(new RetrieveEntityRequest
{
LogicalName = entityName
})).EntityMetadata.PrimaryIdAttribute;
StringBuilder sb = new StringBuilder();
foreach (Guid guid in primaryEntityAttributeIds)
{
sb.AppendLine($@"<value>{guid}</value>");
}
string fetchXml = $@"
<fetch mapping='logical'>
<entity name='{entityName}'>
<no-attrs />
<filter>
<condition attribute='{primaryEntityAttribute}' operator='in'>
{sb}
</condition>
</filter>
</entity>
</fetch> ";
return orgSvc.RetrieveMultiple(new FetchExpression(fetchXml));
}
Обратите внимание, что в этом случае мне нужно сделать отдельный вызов службы (со всеми вытекающими издержками), чтобы получить метаданные сущности, чтобы определить первичный атрибут. Тьфу.
Я хотел бы сделать что-то вроде следующего (фантазия / не работает) метод:
public EntityCollection FantasyFetchEntityRecordsById(IOrganizationService orgSvc, string entityName, IEnumerable<Guid> primaryEntityAttributeIds)
{
StringBuilder sb = new StringBuilder();
foreach (Guid guid in primaryEntityAttributeIds)
{
sb.AppendLine($@"<value>{guid}</value>");
}
// ILLEGAL XML - made up element "primaryEntityAttribute"
string fetchXml = $@"
<fetch mapping='logical'>
<entity name='{entityName}'>
<no-attrs />
<filter>
<primaryEntityAttribute operator='in'>
{sb}
</primaryEntityAttribute>
</filter>
</entity>
</fetch> ";
return orgSvc.RetrieveMultiple(new FetchExpression(fetchXml));
}
Я был бы очень рад использовать другую реализацию QueryBase в сервисе RetrieveMultiple.