LINQ problema options.loadwith
-
22-08-2019 - |
Domanda
Sto scrivendo un sistema di ASP.net basato su tag. Utilizzando il seguente schema db:
Topic <many-many> TagTopicMap <many-many> Tag
In sostanza si tratta di un approccio 3NF (toxi) che ho trovato tra i seguenti: http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html
Ecco il frammento di codice che ho:
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Topic>(t => t.TagTopicMaps);
options.LoadWith<TagTopicMap>(tt => tt.Tag);
var db = new lcDbDataContext();
db.LoadOptions = options;
db.Log = w;
var x = from topic in db.Topics
orderby topic.dateAdded descending
select topic;
ViewData["TopicList"] = x.Take(10);
Quando eseguo questo, il risultato va bene, ma si tratta con 11 query SQL singoli, uno per ottenere l'elenco dei primi 10 argomenti:
SELECT TOP (10) [t0].[Id], [t0].[title], [t0].[dateAdded]
FROM [dbo].[Topics] AS [t0] ORDER BY [t0].[dateAdded] DESC
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.30729.1
E 10 di quelle altre per ottenere i dettagli dei tag singolarmente.
Ho cercato di cambiare le due affermazioni loadwith e fuori, e abbiamo trovato le seguenti cose accadono:
loadwith<topic> : no difference for on or off.
loadwith<tagtopicmap>: 11 Queries when on, much more when off.
In breve, solo la seconda opzione loadwith funziona come previsto. La prima non ha alcun effetto!
Inoltre ho provato a fare il ToList di risultati (). Ma ancora più problemi in uscita:. Per la parte tag dettaglio, è recuperare solo gli elementi UNICHE, tutte quelle modifiche che si ripetono (! Lo stesso tag potrebbero apparire in un certo numero di argomento, ovviamente) sono sceso dalla query
Un ultima cosa, segue è il codice che ho usato in aspx per recuperare i dati, in caso di rendere il ToList risultato (), cambio (IQueryable) a (IList):
<% foreach (var t in (IQueryable)ViewData["TopicList"])
{
var topic = (Topic)t;
%>
<li>
<%=topic.title %> ||
<% foreach (var tt in (topic.TagTopicMaps))
{ %>
<%=tt.Tag.Name%>,
<%} %>
</li>
<%
}
%>
Soluzione
La risposta breve è: LinqToSql ha diverse peculiarità di questo tipo, e, talvolta, è necessario utilizzare il lavoro-around ...
L'opzione Linq2Sql LoadWith provoca semplicemente un inner join tra le tabelle del database, in modo da poter forzare un comportamento simile da rewritting vostra dichiarazione Linq a qualcosa di simile (ti prego di perdonare eventuali errori di battitura, io sono abituato a scrittura Linq nella sintassi VB ... ):
var x = from topic in db.Topics
join topicMap in topic.TagTopicMaps
orderby topic.dateAdded descending
group topicMap by topicMap.topic into tags = Group;
Questa sintassi può essere terribilmente sbagliato, ma l'idea di base è che si forza Linq2Sql per valutare l'unione tra argomenti e TagTopicMaps, e quindi utilizzare il raggruppamento (o "gruppo di join", "lascia", ecc) per conservare l'oggetto gerarchia nel set di risultati.
Altri suggerimenti
Imposta l'EnabledDefferedLoad sulla tua classe DataContext false.
Il problema nel tuo caso è prendere (10). Ecco dalla bocca del cavallo:
La soluzione suggerita è quella di aggiungere Skip (0). Che non ha funzionato per me, ma Skip (1) ha funzionato. Inutile come può essere, almeno so dove il mio problema.