Domanda

Ecco la tabella

Utenti

UserId
UserName
Password
EmailAddress

e il codice ..

public void ChangePassword(int userId, string password){
//code to update the password..
}
È stato utile?

Soluzione

La risposta di Ladislav aggiornato per utilizzare DbContext (introdotto nel EF 4.1):

public void ChangePassword(int userId, string password)
{
  var user = new User() { Id = userId, Password = password };
  using (var db = new MyEfContextName())
  {
    db.Users.Attach(user);
    db.Entry(user).Property(x => x.Password).IsModified = true;
    db.SaveChanges();
  }
}

Altri suggerimenti

Si può dire EF quali proprietà devono essere aggiornati in questo modo:

public void ChangePassword(int userId, string password)
{
  var user = new User { Id = userId, Password = password };
  using (var context = new ObjectContext(ConnectionString))
  {
    var users = context.CreateObjectSet<User>();
    users.Attach(user);
    context.ObjectStateManager.GetObjectStateEntry(user)
      .SetModifiedProperty("Password");
    context.SaveChanges();
  }
}

Hai fondamentalmente due opzioni:

  • andare via EF tutta la strada, in quel caso, si farebbe
    • caricare l'oggetto sulla base del userId fornito - l'intero oggetto viene caricato
    • aggiornare il campo password
    • Salva retro oggetto utilizzando il metodo .SaveChanges() del contesto

In questo caso, sta a EF come gestire questo in dettaglio. Ho appena provato questo, e nel caso a cambiare solo un singolo campo di un oggetto, ciò che crea EF è più o meno quello che ci si crea manualmente, anche - qualcosa come:

`UPDATE dbo.Users SET Password = @Password WHERE UserId = @UserId`

Quindi, EF è abbastanza intelligente per capire che cosa colonne hanno infatti cambiato, e si creerà una dichiarazione di T-SQL per gestire solo gli aggiornamenti che sono in realtà necessari.

  • si definisce una stored procedure che fa esattamente quello che ti serve, in codice T-SQL (solo aggiornare la colonna Password per la UserId dato e nient'altro - in pratica esegue UPDATE dbo.Users SET Password = @Password WHERE UserId = @UserId) e si crea un'importazione funzione per quella stored procedure nella vostra il modello EF e si chiama questa funzione invece di fare la procedura descritta sopra

sto usando in questo modo:

entità:

public class Thing 
{
    [Key]
    public int Id { get; set; }
    public string Info { get; set; }
    public string OtherStuff { get; set; }
}

DbContext:

public class MyDataContext : DbContext
{
    public DbSet<Thing > Things { get; set; }
}

Codice di accesso:

MyDataContext ctx = new MyDataContext();

// FIRST create a blank object
Thing thing = ctx.Things.Create();

// SECOND set the ID
thing.Id = id;

// THIRD attach the thing (id is not marked as modified)
db.Things.Attach(thing); 

// FOURTH set the fields you want updated.
thing.OtherStuff = "only want this field updated.";

// FIFTH save that thing
db.SaveChanges();

Durante la ricerca di una soluzione a questo problema, ho trovato una variazione sul risposta di GONeale attraverso Patrick Desjardins' blog :

public int Update(T entity, Expression<Func<T, object>>[] properties)
{
  DatabaseContext.Entry(entity).State = EntityState.Unchanged;
  foreach (var property in properties)
  {
    var propertyName = ExpressionHelper.GetExpressionText(property);
    DatabaseContext.Entry(entity).Property(propertyName).IsModified = true;
  }
  return DatabaseContext.SaveChangesWithoutValidation();
}
  

" Come si può vedere, si prende come secondo parametro espressione di un   funzione. Questo vi permetterà di utilizzare questo metodo specificando in un Lambda   espressione quale proprietà di aggiornamento. "

...Update(Model, d=>d.Name);
//or
...Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn);

(Una soluzione in qualche modo simile viene anche dato qui: https://stackoverflow.com/a/5749469/2115384 )

Il metodo Attualmente sto usando nel mio codice , esteso per gestire anche (LINQ) Espressioni di tipo ExpressionType.Convert. Questo è stato necessario nel mio caso, ad esempio con le altre proprietà degli oggetti Guid e. Quelli erano 'avvolto' in un Convert () e quindi non gestiti da System.Web.Mvc.ExpressionHelper.GetExpressionText.

public int Update(T entity, Expression<Func<T, object>>[] properties)
{
    DbEntityEntry<T> entry = dataContext.Entry(entity);
    entry.State = EntityState.Unchanged;
    foreach (var property in properties)
    {
        string propertyName = "";
        Expression bodyExpression = property.Body;
        if (bodyExpression.NodeType == ExpressionType.Convert && bodyExpression is UnaryExpression)
        {
            Expression operand = ((UnaryExpression)property.Body).Operand;
            propertyName = ((MemberExpression)operand).Member.Name;
        }
        else
        {
            propertyName = System.Web.Mvc.ExpressionHelper.GetExpressionText(property);
        }
        entry.Property(propertyName).IsModified = true;
    }

    dataContext.Configuration.ValidateOnSaveEnabled = false;
    return dataContext.SaveChanges();
}

In Entity Framework Core, Attach restituisce l'ingresso, quindi tutto ciò che serve è:

var user = new User { Id = userId, Password = password };
db.Users.Attach(user).Property(x => x.Password).IsModified = true;
db.SaveChanges();

Sono in ritardo al gioco qui, ma questo è come sto facendo, ho trascorso un po 'di caccia per una soluzione sono stato entusiasmato con; questo produce una dichiarazione UPDATE solo per i campi che vengono modificate, come si definisce in modo esplicito quello che sono attraverso un concetto di "lista bianca", che è più sicuro per prevenire forma di iniezione web in ogni caso.

Un estratto dal mio repository di dati ISession:

public bool Update<T>(T item, params string[] changedPropertyNames) where T 
  : class, new()
{
    _context.Set<T>().Attach(item);
    foreach (var propertyName in changedPropertyNames)
    {
        // If we can't find the property, this line wil throw an exception, 
        //which is good as we want to know about it
        _context.Entry(item).Property(propertyName).IsModified = true;
    }
    return true;
}

Questo potrebbe essere avvolto in un try..catch, se lo desiderasse, ma io personalmente come il mio visitatore di conoscere le eccezioni in questo scenario.

Si sarebbe chiamato in qualcosa di simile a questa moda (per me, questo era tramite un'API Web ASP.NET):

if (!session.Update(franchiseViewModel.Franchise, new[]
    {
      "Name",
      "StartDate"
  }))
  throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));

So che questo è un vecchio thread, ma mi è stato anche alla ricerca di una soluzione simile e ha deciso di andare con la soluzione @ Doku-così fornito. Sto commentando a rispondere alla domanda posta da @Imran Rizvi, ho seguito @ Doku-modo link che mostra una simile implementazione. domanda di @Imran Rizvi era che stava ottenendo un errore utilizzando la soluzione fornita 'Impossibile convertire espressioni lambda di tipo 'Expression> []', perché non è un tipo delegato'. Ho voluto offrire una piccola modifica che ho fatto a @ così Doku di soluzione che risolve questo errore nel caso in cui nessun altro si imbatte in questo post e decide di usare @ di Doku-così soluzione.

Il problema è il secondo argomento nel metodo Update,

public int Update(T entity, Expression<Func<T, object>>[] properties). 

Per chiamare questo metodo utilizzando la sintassi fornita ...

Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn); 

È necessario aggiungere il 'params' parola chiave di fronte al secondo arugment come così.

public int Update(T entity, params Expression<Func<T, object>>[] properties)

o se non si desidera modificare il metodo di firma quindi per chiamare il metodo Update è necessario aggiungere il ' nuovo ' parola chiave, specificare le dimensioni del matrice, infine utilizzare l'oggetto raccolta inizializzatore sintassi per ogni proprietà aggiornamento come mostrato di seguito.

Update(Model, new Expression<Func<T, object>>[3] { d=>d.Name }, { d=>d.SecondProperty }, { d=>d.AndSoOn });

In @ di Doku-so ad esempio che sta specificando una serie di espressioni quindi è necessario passare le proprietà di aggiornamento in una matrice, a causa della matrice è necessario specificare anche la dimensione della matrice. Per evitare questo si potrebbe anche modificare l'argomento espressione da utilizzare IEnumerable al posto di un array.

Ecco la mia implementazione di @ soluzione Doku-così.

public int Update<TEntity>(LcmsEntities dataContext, DbEntityEntry<TEntity> entityEntry, params Expression<Func<TEntity, object>>[] properties)
     where TEntity: class
    {
        entityEntry.State = System.Data.Entity.EntityState.Unchanged;

        properties.ToList()
            .ForEach((property) =>
            {
                var propertyName = string.Empty;
                var bodyExpression = property.Body;
                if (bodyExpression.NodeType == ExpressionType.Convert
                    && bodyExpression is UnaryExpression)
                {
                    Expression operand = ((UnaryExpression)property.Body).Operand;
                    propertyName = ((MemberExpression)operand).Member.Name;
                }
                else
                {
                    propertyName = System.Web.Mvc.ExpressionHelper.GetExpressionText(property);
                }

                entityEntry.Property(propertyName).IsModified = true;
            });

        dataContext.Configuration.ValidateOnSaveEnabled = false;

        return dataContext.SaveChanges();
    }

Utilizzo:

this.Update<Contact>(context, context.Entry(modifiedContact), c => c.Active, c => c.ContactTypeId);

@ Doku-così fornito un approccio fresco utilizzando di generici, ho usato il concetto di risolvere il mio problema, ma proprio non può usare @ soluzione così Doku come è e sia in questo post e il post collegato nessuno rispose l'uso domande di errore.

Entity Framework tiene traccia delle modifiche su oggetti che si interrogati dal database tramite DbContext. Per esempio se si DbContext nome dell'istanza è DbContext

public void ChangePassword(int userId, string password){
     var user = dbContext.Users.FirstOrDefault(u=>u.UserId == userId);
     user.password = password;
     dbContext.SaveChanges();
}

In EntityFramework Nucleo 2.x non v'è alcuna necessità di Attach:

 // get a tracked entity
 var entity = context.User.Find(userId);
 entity.someProp = someValue;
 // other property changes might come here
 context.SaveChanges();

Abbiamo provato questo in SQL Server e il profiling è:

exec sp_executesql N'SET NOCOUNT ON;
UPDATE [User] SET [someProp] = @p0
WHERE [UserId] = @p1;
SELECT @@ROWCOUNT;

',N'@p1 int,@p0 bit',@p1=1223424,@p0=1

Trova assicura che le entità già caricate non attivano un SELECT e anche attribuisce automaticamente l'entità se necessario (dalla documentazione):

    ///     Finds an entity with the given primary key values. If an entity with the given primary key values
    ///     is being tracked by the context, then it is returned immediately without making a request to the
    ///     database. Otherwise, a query is made to the database for an entity with the given primary key values
    ///     and this entity, if found, is attached to the context and returned. If no entity is found, then
    ///     null is returned.

Io uso ValueInjecter NuGet per iniettare Binding modello nel database utilizzando Entity seguente:

public async Task<IHttpActionResult> Add(CustomBindingModel model)
{
   var entity= await db.MyEntities.FindAsync(model.Id);
   if (entity== null) return NotFound();

   entity.InjectFrom<NoNullsInjection>(model);

   await db.SaveChangesAsync();
   return Ok();
}

Si noti l'utilizzo di convenzione personalizzato che non aggiornare le proprietà se sono nulli dal server.

ValueInjecter v3 +

public class NoNullsInjection : LoopInjection
{
    protected override void SetValue(object source, object target, PropertyInfo sp, PropertyInfo tp)
    {
        if (sp.GetValue(source) == null) return;
        base.SetValue(source, target, sp, tp);
    }
}

Utilizzo:

target.InjectFrom<NoNullsInjection>(source);

Valore injecter V2

questa risposta

Caveat

Non si sa se la proprietà è intenzionalmente autorizzato a nullo o semplicemente non hanno alcun valore di esso. In altre parole, il valore della proprietà può essere sostituito solo con un altro valore, ma non eliminato.

Cercavo stessa e alla fine ho trovato la soluzione

using (CString conn = new CString())
{
    USER user = conn.USERs.Find(CMN.CurrentUser.ID);
    user.PASSWORD = txtPass.Text;
    conn.SaveChanges();
}

mi creda il lavoro per me come un fascino.

La combinazione di diversi suggerimenti vi propongo quanto segue:

    async Task<bool> UpdateDbEntryAsync<T>(T entity, params Expression<Func<T, object>>[] properties) where T : class
    {
        try
        {
            var entry = db.Entry(entity);
            db.Set<T>().Attach(entity);
            foreach (var property in properties)
                entry.Property(property).IsModified = true;
            await db.SaveChangesAsync();
            return true;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine("UpdateDbEntryAsync exception: " + ex.Message);
            return false;
        } 
    }

chiamato da

UpdateDbEntryAsync(dbc, d => d.Property1);//, d => d.Property2, d => d.Property3, etc. etc.);

oppure

await UpdateDbEntryAsync(dbc, d => d.Property1);

oppure

bool b = UpdateDbEntryAsync(dbc, d => d.Property1).Result;
public async Task<bool> UpdateDbEntryAsync(TEntity entity, params Expression<Func<TEntity, object>>[] properties)
{
    try
    {
        this.Context.Set<TEntity>().Attach(entity);
        EntityEntry<TEntity> entry = this.Context.Entry(entity);
        entry.State = EntityState.Modified;
        foreach (var property in properties)
            entry.Property(property).IsModified = true;
        await this.Context.SaveChangesAsync();
        return true;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}
public void ChangePassword(int userId, string password)
{
  var user = new User{ Id = userId, Password = password };
  using (var db = new DbContextName())
  {
    db.Entry(user).State = EntityState.Added;
    db.SaveChanges();
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top