Ho usato un certo numero di entity framework e sono in grado di eseguire facilmente il binding di modelli complessi con l'entità stessa, ma quando si tratta di binding raw di SQL non riesco a trovare alcuna soluzione che stia facendo un binding di relazione complesso db.
ad esempio seguente è un'entità a modellare il codice per la classe di prodotto
var prodResult = db.products.Where(p => p.isActive == true).Select(p => new ComplexProductModel
{
id = p.id,
dateCreated = p.date_created,
datePublished = null,
desc = p.product_desc,
images = db.products_images.Where(pi => pi.prod_id == p.id).Select(pi => pi.prod_img_thumb).ToList(),
summary = p.product_summary,
title = p.product_name + " " + p.product_code
}).ToList();
Questo realizza i dati rispetto al modello complesso che tiene un tipo di lista di stringa o classe all'interno del modello complesso principale secondo i requisiti della query.
Ora ho provato a eseguire la stessa query di generazione con l'esecuzione raw sql, ma il binding per l'oggetto images ha esito negativo.
var rawComplexData = db.Database.SqlQuery<ComplexProductModel>(dynamicSearchQuery).ToList();
C'è una soluzione per questa situazione, quello che sto ottenendo sono 10 righe di dati (per questo esempio) con immagini null che dovrebbero essere 7 righe con immagini duplicate recuperate che vanno in List<string> images
per ComplexProductModel
.
Ecco il modello di prodotto complesso per una migliore comprensione del codice:
public ComplexProductModel {
long? id { get; set; }
string title { get; set; }
string desc { get; set; }
string summary { get; set; }
List<string> images { get; set; }
DateTime? datePublished { get; set; }
DateTime? dateCreated { get; set; }
}
Come da richiesta @tchelidze, ecco dynamicQuery
che è sostanzialmente ciò che ho afferrato da ciò che il framework di entità stava generando da solo:
SELECT
[Project2].[C1] AS [C1],
[Project2].[id] AS [id],
[Project2].[date_created] AS [date_created],
[Project2].[C2] AS [C2],
[Project2].[product_desc] AS [product_desc],
[Project2].[product_summary] AS [product_summary],
[Project2].[C3] AS [C3],
[Project2].[C4] AS [C4],
[Project2].[prod_img_thumb] AS [prod_img_thumb]
FROM ( SELECT
[Extent1].[id] AS [id],
[Extent1].[product_desc] AS [product_desc],
[Extent1].[product_summary] AS [product_summary],
[Extent1].[date_created] AS [date_created],
1 AS [C1],
CAST(NULL AS datetime2) AS [C2],
[Project1].[prod_img_thumb] AS [prod_img_thumb],
CASE WHEN ([Extent1].[product_name] IS NULL) THEN N'' ELSE [Extent1].[product_name] END + N' ' + CASE WHEN ([Extent1].[product_code] IS NULL) THEN N'' ELSE [Extent1].[product_code] END AS [C3],
[Project1].[C1] AS [C4]
FROM [dbo].[products] AS [Extent1]
LEFT OUTER JOIN (SELECT
[Extent2].[prod_id] AS [prod_id],
[Extent2].[prod_img_thumb] AS [prod_img_thumb],
1 AS [C1]
FROM [dbo].[products_images] AS [Extent2] ) AS [Project1] ON [Project1].[prod_id] = [Extent1].[id]
WHERE 1 = [Extent1].[isActive]
) AS [Project2]
ORDER BY [Project2].[id] ASC, [Project2].[C4] ASC
È possibile introdurre un nuovo oggetto, ad esempio chiamiamolo ComplexProductDto
e dovrebbe corrispondere esattamente alla struttura dei risultati della query quando viene restituita da SQL, ad esempio:
// Please adjust...
public class ComplexProductDto
{
public int Id { get; set; }
public int ProductDesc { get; set; }
...
public string ProdImgThumb { get; set; }
}
Ora che i dati verranno appiattiti e non raggruppati, contenenti record duplicati, che è possibile raggruppare in memoria utilizzando Linq.
var rawComplexData = db.Database.SqlQuery<ComplexProductDto>(dynamicSearchQuery).ToList();
var prodResult = rawComplexData
.GroupBy(x => new
{
x.Id,
x.ProductDesc,
// List all but Image...
})
.Select(x => new ComplexProductModel
{
id = x.Key.Id,
desc = x,Key.ProductDesc,
.... // etc.
images = x.Select(i => i.ProdImgThumb).ToList()
});
Il codice potrebbe non essere corretto al 100% ma ottieni il punto. La tecnica consiste nel recuperare i dati non raggruppati e raggrupparli nella struttura desiderata.