Domanda

Ho il seguente scenario:

  1. Le entità vengono caricate dal database.
  2. Uno di questi viene presentato all'utente in un modulo (un controllo utente WPF) in cui l'utente può modificare le proprietà di tale entità.
  3. L'utente può decidere di applicare le modifiche all'entità o di annullare la modifica.

Come implementerei qualcosa del genere con EntityFramework?

Il mio problema è che, quando associo l'interfaccia utente direttamente alle Proprietà dell'entità, ogni modifica viene applicata istantaneamente all'entità. Voglio rimandare al momento in cui l'utente preme OK e l'entità viene convalidata correttamente.

Ho pensato di caricare le Entità con NoTracking e di chiamare ApplyPropertyChanges dopo che l'entità staccata è stata convalidata, ma non sono del tutto sicuro del modo corretto per farlo . Il documento di EntityFramework su MSDN è molto scarso.

Un altro modo a cui potrei pensare è Aggiorna l'entità con StoreWins , ma non mi piace reimpostare le modifiche su Annulla invece di applicarle su Ok.

Qualcuno ha un buon tutorial o esempio?

È stato utile?

Soluzione

Una delle opzioni è quella che hai detto di fare una query senza tracciamento.

ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First(c => c.ID == 232);

Quindi il cliente può modificare 'cliente' come richiesto in memoria, e nulla sta realmente accadendo nel contesto.

Ora, quando vuoi effettivamente apportare la modifica, puoi farlo:

// get the value from the database
var original = ctx.Customers.First(c => c.ID == customer.ID);
// copy values from the changed entity onto the original.
ctx.ApplyPropertyChanges(customer); .
ctx.SaveChanges();

Ora, se non ti senti a tuo agio con la query per motivi di prestazioni o concorrenza, puoi aggiungere un nuovo metodo di estensione AttachAsModified (...) a ObjectContext.

che assomiglia a questo:

public static void AttachAsModified<T>(
    this ObjectContext ctx, 
    string entitySet, 
    T entity)
{
    ctx.AttachTo(entitySet, entity);

    ObjectStateEntry entry = 
            ctx.ObjectStateManager.GetObjectStateEntry(entity);

    // get all the property names
    var propertyNames = 
            from s in entry.CurrentValues.DataRecordInfo.FieldMetadata
            select s.FieldType.Name;

    // mark every property as modified    
    foreach(var propertyName in propertyNames)
    {
        entry.SetModifiedProperty(propertyName);
    }
}

Ora puoi scrivere codice in questo modo:

ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First();
// make changes to the customer in the form
ctx.AttachAsModified("Customers", customer);
ctx.SaveChanges();

E ora non hai concorrenti o query extranous.

L'unico problema ora riguarda le proprietà FK. Probabilmente dovresti guardare il mio indice di suggerimenti per aiuto qui: http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx

Spero che questo aiuti

Alex

Altri suggerimenti

Suggerisco anche IEditableObject e inoltre IDataErrorInfo.

Il modo in cui lo faccio è, fondamentalmente ho un modello per un'entità che accetta l'entità come parametro del costruttore (fondamentalmente un oggetto wrapper).

In BeginEdit, copio le proprietà dell'entità nel mio viewmodel, quindi se faccio CancelEdit, i dati vengono modificati solo nel ViewModel e l'Entità originale non è cambiata. In EndEdit, applico nuovamente le proprietà ViewModel a Entity, o ovviamente solo se la convalida ha avuto esito positivo.

Per la validazione utilizzo i metodi di IDataErrorInfo. Ho appena implementato IDataErrorInfo.Error in modo che controlli ogni nome di proprietà tramite IDataErrorInfo [string columnName] e concatena eventuali messaggi di errore. Se è vuoto, è tutto ok. (non sono sicuro che Error debba essere utilizzato in questo modo, ma lo faccio)

Se ho altre Entità associate alla mia Entità originale, come Customer.Orders, le creo come ViewModels nidificati nel ViewModel dell'Entity originale. Il ViewModel originale chiama i metodi Begin-, Cancel-, EndEdit / Error dei sottomodelli nelle sue implementazioni proprie di quei metodi.

È un po 'più di lavoro, ma penso che ne valga la pena perché tra BeginEdit ed EndEdit, puoi essere abbastanza sicuro che nulla cambia senza che te ne accorga. E avere anche un frammento di codice per le proprietà abilitate per INotifyPropertyChanged aiuta molto.

Il modo normale di farlo è vincolante per qualcosa che implementa IEditableObject . Se e come si adatta al framework di entità, non sono sicuro.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top