I'm trying to translate this PostgreSQL query to Linq using Npgsql:
var result = _dbContext.Substrates.FromSql(@$"SELECT
vs.*,
STRING_AGG(DISTINCT p.product_ref, ', ') AS product_ref,
STRING_AGG(DISTINCT cu.acr, ', ') AS acr
FROM
portal_data.v_substrates vs
LEFT JOIN portal_data.custart c ON c.article_id = vs.id_substrate
LEFT JOIN portal_data.product_components pc ON pc.id_component = vs.id_substrate
LEFT JOIN portal_data.products p ON p.id_product = pc.id_product
LEFT JOIN portal_data.customers cu ON cu.id_customer = c.id_customer
WHERE
c.id_customer = {customerId}
GROUP BY
vs.id_substrate,
vs.substrate_type,
vs.substrate_creation_date,
vs.substrate_status,
vs.substrate_invent_qty,
vs.record_copy_date,
vs.mapped_status
");
As per the Npgsql documentation there is a translation function called EF.Functions.StringToArray() that, if I understood correctly, translates to string_agg(s, '|').
var substrates = from substrate in _dbContext.Substrates
join custart in _dbContext.CustomerArticles on substrate.IdSubstrate equals custart.ArticleId
join component in _dbContext.ProductComponents on substrate.IdSubstrate equals component.IdComponent
join product in _dbContext.Products on component.IdProduct equals product.IdProduct
join customer in _dbContext.Customers on custart.IdCustomer equals customer.Id
where custart.IdCustomer == customerId
select new SubstrateExtended
{
IdSubstrate = substrate.IdSubstrate,
SubstrateType = substrate.SubstrateType,
SubstrateCreationDate = substrate.SubstrateCreationDate,
SubstrateStatus = substrate.SubstrateStatus,
SubstrateInvetoryQuantity = substrate.SubstrateInvetoryQuantity,
RecordCopyDate = substrate.RecordCopyDate,
MappedStatus = substrate.MappedStatus,
ProductRef = EF.Functions.StringToArray(product.ProductRef, ", "),
Acr = EF.Functions.StringToArray(customer.Accronym, ", ")
};
But this doesn't work because EF.Functions.StringToArray() is returning an string[].
Is there a way to translate the SQL query to Linq without retrieve the full list of items for aggregation?
The equivalent is
string.Join, where the second parameter isIEnumerable<string>.But you are also missing a
group by, and your joins in the original query wereleft join.Having said that, it's probably better to rethink your joins and remove the distinct and group by, by using subqueries to pre-aggregate.