salve a tutti
sto lavorando con l'entity framework e possiedo una relazione molti a molti con una tabella articoli e una categorie, per aggiornare gli articoli possiedo un formview con dentro un datalist delle categorie. Il mio problema è che non riesco ad aggiornare la relazione. Ho inserito la relazione nel modelbuilder così:

modelBuilder.Entity<Articoli>().HasMany(t => t.Categorie).WithMany(t => t.Articoli)
.Map(m =>
{
m.ToTable("CategorieArticoli");
m.MapLeftKey("ProgressivoArticolo");
m.MapRightKey("ProgressivoCategoria");
});

ma a quanto pare non basta, nel diagramma dell'entity framework sono presenti le i due oggetti Articoli e Categorie e la relazione molti a molti. Nel formview possiedo il datalist in questo modo e nell'evento updating dell'entityobject vado ad inserire le categorie dell'articolo però quando aggiorno invece di inserire la riga nella relazione aggiunge una nuova categoria dove sbaglio?
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao Paolo,
la relazione mi sembra mappata correttamente. Dovresti mostrare il codice dell'evento Updating che usi per associare una categoria esistente all'articolo.

paolocamping ha scritto:

però quando aggiorno invece di inserire la riga nella relazione aggiunge una nuova categoria

Questo può succedere se ottieni un'istanza della categoria usando il suo costruttore new Categoria(). Facendo così la categoria è un'entità detachata dal contesto, cioè il DbContext non sa della sua esistenza.
Quando finalmente la incontra ed inizia a tracciarla perché l'hai assegnata ad un articolo, penserà che si tratta di una nuova entità da aggiungere al database.

Infatti, se andassi ad esaminare il suo stato, noteresti che è "Added".
//stato vale Added
var stato = tuoDbContext.Entry(categoria).State


Puoi convincere il DbContext del fatto che quella non è una nuova categoria forzando il suo stato su Unchanged. In questo modo non proverà ad inserirla.
//Forzo lo stato su Unchanged
tuoDbContext.Entry(categoria).State = EntityState.Unchanged;
//l'assegno all'articolo
articolo.Categorie.Add(categoria);

Attenzione però perché devi aver correttamente valorizzato le proprietà che costituiscono la chiave primaria di categoria, altrimenti non riuscirai ad "ingannare" il DbContext e avrai degli errori in fase di salvataggio.

Dato che "smanettare" con lo stato delle entità richiede una certa consapevolezza su come funziona il tracciamento delle modifiche in un DbContext, potresti trovare quest'altra soluzione più facile da usare. Scegli tu.
//per prima cosa recupero la categoria dal db
var categoria = tuoDbContext.Categorie.Single(c => c.Id == idCategoria);
//e poi l'assegno all'articolo
articolo.Categorie.Add(categoria);

In questo modo vai a recuperare l'entità dal database. Il DbContext saprà per certo che quell'entità è già esistente e che non va reinserita. Infatti l'ha appena recuperata lui stesso.
Questo però significa anche che Entity Framework dovrà effettuare una o più ulteriori chiamate al database (in base a quante categorie devi associare) prima che tu possa salvare i risultati.

ciao,
Moreno
Modificato da BrightSoul il 22 marzo 2015 10.16 -

Enjoy learning and just keep making
ciao Moreno
grazie per la riposta, il problema è che non ho capito come accedere al dbcontext durante l'aggiornamento del entitydatasource per passargli le categorie che dici te. Avevo già provato a fare una cosa del genere ma ovviamente istanziando un nuovo dbcontext nell'updating del entitydataobject provaca un errore di connessione ovviamente.
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao Paolo,

paolocamping ha scritto:

istanziando un nuovo dbcontext nell'updating del entitydataobject provaca un errore di connessione ovviamente

In realtà dovresti poter creare quanti DbContext desideri, non sono sicuro di quale sia il motivo per cui ti stia dando un errore di connessione.
Posta un po' di codice, così magari il problema è più chiaro.

La cosa migliore sarebbe che tu creassi una sola istanza del DbContext durante l'evento ContextCreating dell'EntityDataSource, e conservare il riferimento a quell'istanza in un campo.
Poi, durante l'evento Updating, andrai ad usare quel campo per interagire con l'istanza che avevi creato prima.

Leggi qui a proposito dell'evento ContextCreating.
http://blogs.msdn.com/b/webdev/archive/2012/09/13/how-to-use-the-entitydatasource-control-with-entity-framework-code-first.aspx

ciao,
Moreno

Enjoy learning and just keep making
avevo già provato il procedimento che dici te però mi provoca un errore strano: Impossibile convertire implicitamente il tipo 'System.Data.Entity.Core.Objects.ObjectContext' in 'System.Data.Objects.ObjectContext'

da cosa può essere dovuto? io utilizzo l'EF6 asp.net framework 4.5

il codice dove vorrei agire è qui dove in teoria vorrei passargli le categorie dell'articolo
 protected void uxGestioneArticoli_Updating(object sender, EntityDataSourceChangingEventArgs e)
    {

    }

in teoria potrei anche passargliele direttamente tramite il codice asp.net con uno usercontrol però non funziona neanche quello:
                                        <tr>
                                            <td style="padding-left:20px; padding-bottom:20px">
                                                <pers:SelezionaCategorie ID="uxSelezionaCategorie" runat="server" CategorieSelezionate='<%# Bind("Categorie") %>' />
                                            </td>
                                        </tr>


ovviamente ho impostato l'entitydatasource in modo da includere le categorie ma forse non le ho collegate correttamente:

<asp:EntityDataSource ID="uxGestioneArticoli" runat="server" ConnectionString="name=blogEntities" DefaultContainerName="blogEntities" EntitySetName="Articoli" OnInserted="uxGestioneArticoli_Inserted" EnableInsert="True" OnInserting="uxGestioneArticoli_Inserting" EnableUpdate="True" OnUpdated="uxGestioneArticoli_Updated" OnUpdating="uxGestioneArticoli_Updating" Include="Categorie" EnableFlattening="False" Select="" Where="it.progressivoarticolo = @progressivoarticolo" OnContextCreating="uxGestioneArticoli_ContextCreating">
                                <WhereParameters>
                                    <asp:QueryStringParameter Name="progressivoarticolo" QueryStringField="progressivoarticolo" DbType="Int16" />
                                </WhereParameters>
                            </asp:EntityDataSource>


in teoria le soluzioni alternative ce ne sono tante ma vorrei cercare di capire perchè non funziona
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao Paolo,
perdona l'attesa, sono stati giorni concitati.

paolocamping ha scritto:

Impossibile convertire implicitamente il tipo 'System.Data.Entity.Core.Objects.ObjectContext' in 'System.Data.Objects.ObjectContext'

Già, come puoi leggere qui, l'ObjectContext ha cambiato namespace nel passaggio da EF5 a EF6.

Tu al momento hai un EntityDataSource che si aspetta di lavorare con l'ObjectContext di EF5, ma tu gli stai fornendo la versione di EF6.

Dovresti usare un EntityDataSource aggiornato, che supporti EF6. Scaricalo da NuGet, lo trovi qui:
http://www.nuget.org/packages/Microsoft.AspNet.EntityDataSource/

ciao,
Moreno

Enjoy learning and just keep making
ciao Moreno in effetti con l'EntityDataSource aggiornato non da errore, però a questo punto ho provato a fare l'attach e il deattach delle categorie che ho selezionato, io avevo pensato a fare un istruzione del genere ma non funziona...

sempre nell'evento updating delle dell'EntityDataSource

Categorie categoria = new Categorie();
categoria.ProgressivoCategoria = 10;
categoria.NomeCategoria = "estate";

e.Context.AttachTo("Categorie", categoria);


inoltre la mia domanda è: se devo impazzire per salvare una semplice relazione many-to-many non mi conviene fare una semplice stored procedure con un classico merge? che vantaggi ho ad impazzire con l'EF6??
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,

paolocamping ha scritto:
io avevo pensato a fare un istruzione del genere ma non funziona...

Sembra corretto; posta il testo dell'errore che ricevi.
Potrebbe essere che stai provando a fare l'Attach di una categoria già tracciata dal contesto, perché già assegnata al prodotto.
Comunque è solo una congettura; bisogna vedere l'errore.

In quel frammento di codice poi manca l'effettiva associazione tra il prodotto e la categoria in questione. Puoi anche tralasciare la riga in cui assegni il NomeCategoria perché non è necessario. Infatti, dato che hai fatto l'Attach, l'entità si troverà nello stato di Unchanged e perciò non verrà reinviata al database per l'aggiornamento. L'importante è valorizzare la/e proprietà che rappresentano la chiave primaria (credo sia ProgressivoCategoria, in questo caso).

paolocamping ha scritto:

che vantaggi ho ad impazzire con l'EF6??

Probabilmente tu sei molto più ferrato con l'uso di T-SQL e ti sembra che fare la stessa cosa con Entity Framework sia inutilmente più complicato.
Devi anche guardare la situazione in prospettiva: tutti questi "problemi" che stai avendo ora li supererai velocemente una volta compreso in meccanismo che Entity Framework usa per tracciare le entità nel contesto.

Dal mio punto di vista, EF offre la comodità di lavorare con grafi di oggetti e ciò lo preferisco rispetto allo scrivere stored procedure T-SQL che vanno testate e che non posso aggiungere al controllo di versione (a meno che ovviamente non abbia creato per esempio Database Project all'interno di Visual Studio).

ciao,
Moreno
Modificato da BrightSoul il 03 aprile 2015 20.27 -

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.