205 messaggi dal 03 ottobre 2006
Potete indicarmi dove trovare un esempio che mostri come fare il databinding di una gridview basata sul join fra due entità? Mi spiego meglio, uso EF 6 su web forms e c#. Ho due tabelle che vengono create sul DB attraverso code first. Le tabelle sono relazionate come molti a molti quindi alle due classi ho aggiunto due collection navigation property per poter navigare.
Ecco le classi:
public class Evento
{
public Evento()
{
this.Tesserati = new HashSet<Tesserato>();
}
[Key]
public double Id { get; set; }
public string Title { get; set; }
public string Alias { get; set; }
public virtual ICollection<Tesserato> Tesserati { get; set; }
}

public class Tesserato
{

public Tesserato()
{
this.Eventi = new HashSet<Evento>();
}

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int TesseratoID { get; set; }
public string Evento { get; set; }
public virtual ICollection<Evento> Eventi { get; set; }
}
Purtroppo le due classi non hanno in comune le due chiavi primarie bensì Evento.Title e Tesserato.Evento
quindi ho aggiunto questo pezzo di codice in modo che code first mi crei la tabella di join EventoTesseratoes con le mie due colonne

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Evento>()
.HasMany<Tesserato>(s => s.Tesserati)
.WithMany(c => c.Eventi)
.Map(cs =>
{
cs.MapLeftKey("Title");
cs.MapRightKey("Evento");
cs.ToTable("EventoTesseratoes");
});
}

se questa è la definizione di ListEventi nel DBContext
public DbSet<Evento> ListEventi { get; set; }

Vorrei poter mostrare in una gridview alcune colonne della tabella Evento e alcune di Tesserati ma la seguente query
ListEventi.Include("Tesserati")
che mi aspettavo restituisse una entità "Evento" formata dalla inner join delle due tabelle mi restituisce la colonna Tesserati vuota probabilmente perchè di default esegue la inner join sulle chiavi primarie, ma se è così, come cambio la query perchè la inner join la faccia sulle colonne Title e Evento ?

Sono alle prime armi ma davvero non trovo esempi dopo numerose ricerche.
Grazie
11.050 messaggi dal 09 febbraio 2002
Contributi
Ciao,

probabilmente perchè di default esegue la inner join sulle chiavi primarie

No, dato che hai mappato esplicitamente le chiavi "Title" ed "Evento" credo che stia usando quelle per fare la join. Forse il motivo per cui la proprietà Tesserati risulta null è che la join non ha prodotto corrispondenze. Per esempio può essere che le colonne contengono valori differenti, ad esempio in una c'è uno spazio.

Comunque, per evitare di andare a tentantivi, fai scrivere il log delle query a Entity Framework, così le puoi vedere ed eseguire da Sql Server Management Studio e renderti conto di quali righe stia restituendo.

Il log per EF6 si abilita così:
https://docs.microsoft.com/en-us/ef/ef6/fundamentals/logging-and-interception#context-log-property

ciao,
Moreno

Enjoy learning and just keep making
205 messaggi dal 03 ottobre 2006
Grazie Moreno
stavo proprio seguendo la strada che mi hai suggerito e ti farò sapere ma in realtà parallelamente sto usando linq4 per interrogare lo stesso db con le stesse query ed avere risultati più diretti, ebbene
questa query:
ListEventi.Include("Tesserati")
mi restituisce come dovrebbe una entità Evento con tutte le sue colonne ma l'ultima, "Tesserati", è vuota e le righe sono tante quante quelle della tabella Evento quindi direi che sta facendo la join sulle chiavi primarie che sicuramente non hanno nulla in comune
Inoltre ho trovato qui http://www.entityframeworktutorial.net/entity-relationships.aspx una nota che recita questo:
Note: Entity framework supports many-to-many relationships only when the joining table (StudentCourse in this case) does NOT include any columns other than PKs of both tables. If the join tables contain additional columns, such as DateCreated, then the EDM creates an entity for the middle table as well and you will have to manage CRUD operations for many-to-many entities manually.

Per questo temo che stia facendo la query sbagliata... in ogni caso fra poco lo verifico come hai suggerito tu.

In definitiva, questa query sarebbe perfetta
from c in ListEventi
from s in ListTesserati
where s.Evento == c.Title
select new {c,s}
perchè da linq4 contiene esattamente la join che cerco ma al di la del fatto che volevo imparare ad usare la Include, genera un oggetto che non so di che tipo sia e quindi non so come associarlo alla gridview


Grazie
11.050 messaggi dal 09 febbraio 2002
Contributi
Ciao,


genera un oggetto che non so di che tipo sia

Anziché usare un tipo anonimo potresti crearti una classe apposita che contenga due proprietà, una del tipo Evento e una del tipo di Tesserato.

public class EventoTesseratoDto {
  public Evento Evento { get; set; }
  public Tesserato Tesserato { get; set; }
}


E poi lo usi nella clausola select.
...
select new EventoTesseratoDto { Evento = c, Tesserato = s};


Il tipo risultante dalla query LINQ sarà un IEnumerable<EventoTesseratoDto>.

ciao,
Moreno

Enjoy learning and just keep making
205 messaggi dal 03 ottobre 2006
Ottimo, grazie Moreno
quindi Linq To Entities non può creare oggetti di una classe di cui esiste una entità cioè:

...select new Evento....

ma se io creo una classe diversa come hai proposto tu posso tranquillamente fare

...select new EventoTesseratoDto { Evento = c, Tesserato = s};

Così funziona
grazie
11.050 messaggi dal 09 febbraio 2002
Contributi
Beh, puoi anche fare new Evento. Semplicemente questa entità non verrà tracciata dal DbContext dato che non è stato lui stesso a materializzarla, e quindi non potrai sfruttare alcune funzionalità tipo il lazy loading.

Comunque, dato che avevi creato un tipo anonimo ho pensato che volessi avere le istanze di Evento e Tesserato su due proprietà di un unico oggetto. Per questo ti ho proposto di usare il EventoTesseratoDto ma puoi usare certamente anche Evento.

ciao,
Moreno

Enjoy learning and just keep making
205 messaggi dal 03 ottobre 2006
mi sa che allora c'è ancora qualcosa che non mi è chiaro...
Ho creato questa classe
public class EventoTesserati
{
public Evento Ev { get; set; }
public ICollection<Tesserato> Te { get; set; }
}

la seguente query pare funzionante
var data = from p in _db.ListEventi
from s in _db.ListTesserati
where s.Evento == p.Title
select new EventoTesserati { Ev = p, Te = p.Tesserati };

Devo mettere la Icollection<Tesserato> perchè ogni Evento può contenere più tesserati e il mio obiettivo finale è quello di fare due gridview innestate per mostrare, quando clicco su un evento, l'elenco dei tesserati iscritti.
Quindi, se la query sopra funziona, e l'ho provata con Linq4, come faccio a fare per esempio il databinding della prima gridview?

<asp:GridView ID="EventiList" runat="server" DataKeyNames="Ev.Id" ItemType="SkipperClub.Models.EventoTesserati">
<Columns>
<asp:BoundField DataField="Ev.Id" HeaderText="Id" SortExpression="Ev.Id" />
...
...
</Columns>
</GridView>

Ovvero qual'è la sintassi per richiamare le proprietà di Ev a partire dal datakeynames?
11.050 messaggi dal 09 febbraio 2002
Contributi
Beh, non c'è differenza rispetto a prima.
Usando EventoTesseratoDto c'è una proprietà chiamata Evento di tipo Evento.
Usando EventoTesserati c'è una proprietà chiamata Ev di tipo Evento.

Il binding dovrebbe funzionare allo stesso modo. Che errore ti dà precisamente?

ciao,
Moreno

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.