net - tutorial c# mvc




Entity Framework 5 Aggiornamento di un record (5)

A seconda del tuo caso d'uso, si applicano tutte le soluzioni di cui sopra. Questo è come faccio di solito però:

Per il codice lato server (ad es. Un processo batch) di solito carico le entità e lavoro con i proxy dinamici. Di solito nei processi batch è necessario caricare i dati comunque nel momento in cui viene eseguito il servizio. Provo a caricare in batch i dati anziché utilizzare il metodo find per risparmiare tempo. A seconda del processo, utilizzo un controllo di concorrenza ottimistico o pessimistico (utilizzo sempre ottimistico tranne che per scenari di esecuzione paralleli in cui è necessario bloccare alcuni record con semplici istruzioni SQL, tuttavia è raro). A seconda del codice e dello scenario, l'impatto può essere ridotto quasi a zero.

Per gli scenari lato client, hai alcune opzioni

  1. Usa i modelli di vista. I modelli dovrebbero avere una proprietà UpdateStatus (non modificata-inserita-aggiornata-cancellata). È responsabilità del client impostare il valore corretto in questa colonna in base alle azioni dell'utente (insert-update-delete). Il server può interrogare il db per i valori originali o il client deve inviare i valori originali al server insieme alle righe modificate. Il server deve allegare i valori originali e utilizzare la colonna UpdateStatus per ogni riga per decidere come gestire i nuovi valori. In questo scenario uso sempre la concorrenza ottimistica. Questo farà solo l'inserimento - aggiorna - cancella le istruzioni e non le selezioni, ma potrebbe essere necessario un codice intelligente per percorrere il grafico e aggiornare le entità (dipende dal tuo scenario - applicazione). Un mappatore può aiutare ma non gestisce la logica CRUD

  2. Usa una libreria come breeze.js che nasconde la maggior parte di questa complessità (come descritto in 1) e cerca di adattarla al tuo caso d'uso.

Spero che sia d'aiuto

Ho esplorato diversi metodi di modifica / aggiornamento di un record all'interno di Entity Framework 5 in un ambiente ASP.NET MVC3, ma finora nessuno di essi ha spuntato tutte le caselle di cui ho bisogno. Spiegherò perché.

Ho trovato tre metodi a cui menzionerò i pro e i contro:

Metodo 1: carica il record originale, aggiorna ogni proprietà

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    original.BusinessEntityId = updatedUser.BusinessEntityId;
    original.Email = updatedUser.Email;
    original.EmployeeId = updatedUser.EmployeeId;
    original.Forename = updatedUser.Forename;
    original.Surname = updatedUser.Surname;
    original.Telephone = updatedUser.Telephone;
    original.Title = updatedUser.Title;
    original.Fax = updatedUser.Fax;
    original.ASPNetUserId = updatedUser.ASPNetUserId;
    db.SaveChanges();
}    

Professionisti

  • Può specificare quali proprietà cambiano
  • Le viste non devono contenere ogni proprietà

Contro

  • 2 x query sul database per caricare l'originale quindi aggiornarlo

Metodo 2: carica il record originale, imposta i valori modificati

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    db.Entry(original).CurrentValues.SetValues(updatedUser);
    db.SaveChanges();
}

Professionisti

  • Solo le proprietà modificate vengono inviate al database

Contro

  • Le viste devono contenere ogni proprietà
  • 2 x query sul database per caricare l'originale quindi aggiornarlo

Metodo 3: Allegare record aggiornati e impostare lo stato su EntityState.Modified

db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();

Professionisti

  • 1 x query sul database da aggiornare

Contro

  • Non è possibile specificare quali proprietà cambiano
  • Le viste devono contenere ogni proprietà

Domanda

La mia domanda per voi ragazzi; c'è un modo pulito per raggiungere questo insieme di obiettivi?

  • Può specificare quali proprietà cambiano
  • Le viste non devono contenere ogni proprietà (come la password!)
  • 1 x query sul database da aggiornare

Capisco che questa sia una cosa da sottolineare, ma potrei mancare una soluzione semplice a questo. Se non il metodo prevarrà ;-)


Ho aggiunto un metodo di aggiornamento aggiuntivo alla mia classe base del repository simile al metodo di aggiornamento generato da Scaffolding. Invece di impostare l'intero oggetto su "modificato", imposta un insieme di proprietà individuali. (T è un parametro generico di classe).

public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
    Context.Set<T>().Attach(obj);

    foreach (var p in propertiesToUpdate)
    {
        Context.Entry(obj).Property(p).IsModified = true;
    }
}

E quindi per chiamare, ad esempio:

public void UpdatePasswordAndEmail(long userId, string password, string email)
{
    var user = new User {UserId = userId, Password = password, Email = email};

    Update(user, u => u.Password, u => u.Email);

    Save();
}

Mi piace un viaggio nel database. Probabilmente è meglio farlo con i modelli di vista, però, per evitare di ripetere serie di proprietà. Non l'ho ancora fatto perché non so come evitare di portare i messaggi di convalida sui validatori del mio modello di vista nel mio progetto di dominio.


Solo per aggiungere all'elenco delle opzioni. Puoi anche prendere l'oggetto dal database e utilizzare uno strumento di mappatura automatica come Auto Mapper per aggiornare le parti del record che vuoi cambiare.


Stai cercando:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();

public interface IRepository
{
    void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class;
}

public class Repository : DbContext, IRepository
{
    public void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class
    {
        Set<T>().Attach(obj);
        propertiesToUpdate.ToList().ForEach(p => Entry(obj).Property(p).IsModified = true);
        SaveChanges();
    }
}




entity-framework-5