Frage

Hier ist die Tabelle

Nutzer

UserId
UserName
Password
EmailAddress

und der Code ..

public void ChangePassword(int userId, string password){
//code to update the password..
}
War es hilfreich?

Lösung

Ladislav Antwort aktualisiert DbContext verwenden (eingeführt in 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();
  }
}

Andere Tipps

Sie können EF sagen, welche Eigenschaften haben auf diese Weise aktualisiert werden:

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();
  }
}

Sie haben grundsätzlich zwei Möglichkeiten:

  • die EF Art und Weise den ganzen Weg gehen, in diesem Fall würden Sie
    • laden Sie das Objekt auf der Grundlage der userId vorgesehen - das gesamte Objekt geladen wird,
    • Aktualisieren der password Feld
    • save das Objekt wieder im Kontext des .SaveChanges() Methode mit

In diesem Fall ist es zu EF auf, wie dies im Detail zu behandeln. Ich dies nur getestet, und in dem Fall, dass ich nur ein einzelnes Feld eines Objekts ändern, was EF schafft, ist ziemlich viel, was Sie manuell erstellen würden, auch - so etwas wie:

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

So EF ist intelligent genug, um herauszufinden, was Spalt tatsächlich geändert hat, und es wird eine T-SQL-Anweisung zu behandeln nur das Updates erstellen, die in der Tat notwendig.

  • definieren Sie eine gespeicherte Prozedur, die genau das tut, was Sie brauchen, in T-SQL-Code (Update nur die Password Spalte für die gegebene UserId und sonst nichts - im Grunde führt UPDATE dbo.Users SET Password = @Password WHERE UserId = @UserId) und Sie erstellen eine Funktion Import für die gespeicherte Prozedur in Ihrer EF-Modell und Sie diese Funktion aufrufen, anstatt die Schritte tun oben skizzierte

ich verwende diese:

Einheit:

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; }
}

Zugriffscode:

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();

Während dieses Problem nach einer Lösung suchen, fand ich eine Variation auf GONeale Antwort durch 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();
}
  

" Wie Sie sehen können, dauert es als zweiten Parameter ein Ausdruck einer   Funktion. Auf diese Weise kann diese Methode verwenden, indem sie in einem Lambda Angabe   Ausdruck, die Eigenschaft zu aktualisieren. "

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

(Eine ähnliche Lösung auch hier gegeben: https://stackoverflow.com/a/5749469/2115384 )

Die Methode, die ich zur Zeit in meinem eigenen Code am , erstreckte sich auch auf handhaben (Linq) Ausdrücke vom Typ ExpressionType.Convert. Dies war in meinem Fall notwendig, zum Beispiel mit Guid und anderen Objekteigenschaften. Das war 'eingewickelt' in der Convert () und daher nicht von System.Web.Mvc.ExpressionHelper.GetExpressionText behandelt.

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();
}

Im Entity Framework Core Attach gibt den Eintrag, so alles, was Sie brauchen, ist:

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

Ich bin zu spät, um das Spiel hier, aber das ist, wie ich es tue, verbrachte ich während der Jagd für eine Lösung, die ich mit satisified wurde; Dies erzeugt eine UPDATE Aussage nur für die Felder, die geändert werden, wie Sie explizit definieren, was sie durch eine „weiße Liste“ -Konzept sind, die sicherer ist sowieso Injektions Webformular zu verhindern.

Ein Auszug aus meinem ISession Daten-Repository:

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;
}

Dies könnte in einem try..catch eingewickelt werden, wenn Sie dies wünschen, aber ich persönlich mag meine Anrufer über die Ausnahmen in diesem Szenario kennen.

Es wäre in so etwas wie diese Art und Weise genannt werden (für mich war dies über eine ASP.NET Web API):

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

Ich weiß, das ist ein alter Thread, aber ich war auch auf der Suche nach einer ähnlichen Lösung und entschied sich mit der Lösung zu gehen @ Doku-so zur Verfügung gestellt. Ich kommentiere die Frage nach @Imran Rizvi nicht beantwortet zu werden, folgte ich @ Doku-so Link, dass eine ähnliche Umsetzung. @Imran Rizvi Frage war, dass er einen Fehler bekommen die bereitgestellte Lösung unter Verwendung des Ausdrucks ‚Kann Lambda Ausdruck Typ nicht konvertieren‚> []‘, weil es nicht eine Art delegieren ist‘. Ich wollte eine kleine Änderung biete ich gemacht @ Doku-so-Lösung, dass behebt diesen Fehler, falls jemand über dieses Thema kommt und entscheidet @ Doku-so-Lösung zu verwenden.

Das Problem ist, das zweite Argument in der Update-Methode,

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

Um diese Methode rufen Sie die Syntax zur Verfügung gestellt ...

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

Sie müssen hinzufügen ‚params‘ Schlüsselwort vor dem zweiten arugment als so.

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

oder, wenn Sie nicht die Methode Signatur ändern möchten dann die Update-Methode aufrufen müssen Sie hinzufügen ‚ neue ‘ Schlüsselwort, geben Sie die Größe der Array, dann verwenden Sie schließlich die Sammlung Objektinitialisierer Syntax für jede Eigenschaft zu aktualisieren, wie unten zu sehen.

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

@ Doku-so das Beispiel er eine Reihe von Ausdrücken spezifiziert, so dass Sie die Eigenschaften Aktualisierung in einem Array übergeben werden muss, weil der Array Sie auch die Größe des Arrays angeben müssen. Um dies zu vermeiden Sie könnten auch den Ausdruck Argument ändern IEnumerable verwenden anstelle eines Arrays.

Hier ist meine Implementierung von @ Doku-so-Lösung.

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();
    }

Verbrauch:

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

@ Doku-so einen kühlen Ansatz generic die vorgesehen ist, habe ich das Konzept mein Problem zu lösen, aber man kann einfach nicht verwenden @ Doku-so-Lösung wie und sowohl in diesem Beitrag und der verlinkten Beitrag nicht beantworten man die Nutzung Fehler Fragen.

Entity Framework verfolgt Ihre Änderungen auf Objekte, die Sie aus der Datenbank über DbContext abgefragt. Wenn Sie zum Beispiel DbContext Instanzname ist DbContext

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

In EntityFramework Core-2.x gibt es keine Notwendigkeit für Attach ist:

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

versucht, diese in SQL Server und Profilierungs es:

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

stellt sicher finden, die bereits geladen Entitäten auslösen keine SELECT und auch misst automatisch die Einheit bei Bedarf (aus der Dokumentation):

    ///     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.

Ich benutze ValueInjecter nuget einzuspritzen Bindungsmodell in der Datenbank Entity mit folgenden:

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();
}

Beachten Sie die Verwendung von benutzerdefinierter Konvention, die nicht Eigenschaften nicht aktualisiert Wenn sie null vom 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);
    }
}

Verbrauch:

target.InjectFrom<NoNullsInjection>(source);

Wert Injecter V2

diese Antwort

Caveat

Sie werden nicht wissen, ob die Eigenschaft absichtlich auf null gelöscht oder es hat einfach keinen Wert es. Mit anderen Worten, kann der Wert die Eigenschaft nur mit einem anderen Wert, aber nicht gelöscht ersetzt werden.

Ich war auf der Suche für gleiche und schließlich fand ich die Lösung

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

glauben Sie mir es für mich wie ein Zauber funktionieren.

Die Kombination mehrere Vorschläge Ich schlage die folgende:

    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;
        } 
    }

genannt durch

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

oder durch

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

oder durch

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();
  }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top