我正在尝试使用 Npgsql 将此 PostgreSQL 查询转换为 Linq:
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
");
根据 Npgsql 文档,有一个名为
EF.Functions.StringToArray()
的翻译函数,如果我理解正确的话,它会翻译为 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, ", ")
};
但这不起作用,因为
EF.Functions.StringToArray()
返回一个 string[]
。
有没有办法将 SQL 查询转换为 Linq,而无需检索用于聚合的完整项目列表?
等价的是
string.Join
,其中第二个参数是IEnumerable<string>
。
但是您还缺少
group by
,并且原始查询中的连接是 left join
。
var substrates =
from substrate in _dbContext.Substrates
join custart1 in _dbContext.CustomerArticles on substrate.IdSubstrate equals custart.ArticleId into j1 from custart in j1.DefaultIfEmpty()
join component1 in _dbContext.ProductComponents on substrate.IdSubstrate equals component.IdComponent into j2 from component in j2.DefaultIfEmpty()
join product1 in _dbContext.Products on component.IdProduct equals product.IdProduct into j3 from product in j3.DefaultIfEmpty()
join customer1 in _dbContext.Customers on custart.IdCustomer equals customer.Id into j4 from customer in j4.DefaultIfEmpty()
where custart.IdCustomer == customerId
group new { custart, component, product, customer } by substrate into g
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 = string.Join(", ", g.Select(t => t.product.ProductRef).Distinct()),
Acr = string.Join(", ", g.Select(t => t.customer.Accronym).Distinct())
};
话虽如此,最好重新考虑您的连接并通过使用子查询进行预聚合来删除不同的和分组依据。
var substrates =
from substrate in _dbContext.Substrates
where custart.IdCustomer == customerId
let acr = string.Join(", ",
from custart in _dbContext.CustomerArticles
join customer1 in _dbContext.Customers on custart.IdCustomer equals customer.Id
where substrate.IdSubstrate == custart.ArticleId
select customer.Accronym
)
let productRef = string.Join(", ",
from component1 in _dbContext.ProductComponents
join product1 in _dbContext.Products on component.IdProduct equals product.IdProduct
where substrate.IdSubstrate == component.IdComponent
select product.ProductRef
)
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 = productRef,
Acr = acr
};