Pregunta

Aquí está la tabla

Usuarios

UserId
UserName
Password
EmailAddress

y el código ..

public void ChangePassword(int userId, string password){
//code to update the password..
}
¿Fue útil?

Solución

respuesta de Ladislav actualizado para utilizar DbContext (introducido en 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();
  }
}

Otros consejos

Se puede decir EF qué propiedades tienen que ser actualizados de esta manera:

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

Usted tiene básicamente dos opciones:

  • seguir el camino hasta el final EF, en ese caso, lo haría
    • cargar el objeto basado en la userId proporcionado - todo el objeto se carga
    • actualizar el campo password
    • Guardar la parte posterior de objetos mediante el método de .SaveChanges() el contexto

En este caso, le toca a EF cómo manejar esto en detalle. Acabo de probar esto, y en el caso únicamente cambio de un único campo de un objeto, lo que crea EF es más o menos lo que se crea manualmente, también - algo como:

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

Así EF es lo suficientemente inteligente como para saber lo que las columnas han cambiado de hecho, y se creará una instrucción T-SQL para manejar sólo aquellas actualizaciones que son, de hecho, es necesario.

  • se define un procedimiento almacenado que hace exactamente lo que necesita, en el código T-SQL (solo actualizar la columna Password para la UserId dado y nada más - básicamente ejecuta UPDATE dbo.Users SET Password = @Password WHERE UserId = @UserId) y se crea una importación de función para ese procedimiento almacenado en su modelo de EF y se llama a esta función en lugar de hacer los pasos descritos anteriormente

Estoy usando esto:

entidad:

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

Código de acceso:

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

Si bien la búsqueda de una solución a este problema, he encontrado una variación en la respuesta de GONeale través de 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();
}
  

" Como se puede ver, se toma como segundo parámetro una expresión de una   función. Esto le permitirá utilizar este método mediante la especificación de una Lambda   expresión que la propiedad de actualización. "

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

(también se da Una solución algo similar aquí: https://stackoverflow.com/a/5749469/2115384 )

El método Actualmente estoy usando en mi propio código , se extendió también a manejar las expresiones (LINQ) de tipo ExpressionType.Convert. Esto era necesario en mi caso, por ejemplo, con Guid y otras propiedades del objeto. Esos fueron 'envuelto' en un Convert () y por lo tanto no se maneja por 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();
}

En la entidad Marco de base, vuelve Attach la entrada, por lo que todo lo que necesita es:

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

Se me hace tarde para el juego aquí, pero así es como lo estoy haciendo, pasé un tiempo de caza para una solución que estaba satisfechos con; Esto produce una declaración UPDATE solamente para los campos que se cambian, tal como se define explícitamente lo que son a través de un concepto de "lista blanca", que es más seguro para prevenir forma de inyección web de todos modos.

Un extracto de mi repositorio de datos 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;
}

Esto podría ser envuelto en una try..catch si así lo deseaban, pero yo personalmente como mi persona que llama para saber sobre las excepciones en este escenario.

Se llamaría en algo como esto de la moda (para mí, esto era a través de una API Web ASP.NET):

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

Sé que esto es un hilo viejo, pero yo también estaba buscando una solución similar y decidió ir con la solución @ Doku-así lo dispone. Estoy comentando para responder a la pregunta hecha por @Imran Rizvi, he seguido @ Doku-tan enlace que muestra una implementación similar. La pregunta de @Imran Rizvi era que estaba recibiendo un error al usar la solución aportada 'No se puede convertir la expresión Lambda de Tipo 'Expresión> []' porque no es un tipo de delegado. Quería ofrecer una pequeña modificación que hice a @-Doku modo de solución que corrige este error en caso de que alguien más viene con este post y decide utilizar @ solución de Doku-so.

El tema es el segundo argumento en el método de actualización,

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

Para llamar a este método utilizando la sintaxis proporcionada ...

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

Debe añadir el 'params' palabra clave delante de la segunda arugment como tal.

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

o si no desea cambiar la firma del método a continuación, llamar al método de actualización es necesario agregar el ' nueva ' palabra clave, especifique el tamaño de la array, y finalmente utilizar el objeto colección inicializador sintaxis para cada propiedad para la actualización como se ve a continuación.

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

En el ejemplo de @ Doku-por lo que está especificando un conjunto de expresiones por lo que debe pasar las propiedades de actualización en una matriz, a causa de la matriz también debe especificar el tamaño de la matriz. Para evitar esto se podría también cambiar el argumento de expresión a utilizar IEnumerable en lugar de una matriz.

Aquí está mi implementación de la solución de @ Doku-so.

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

Uso:

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

@ Doku-así lo dispone un enfoque fresco usando de genéricos, que utiliza el concepto de resolver mi problema, sino que simplemente no se puede utilizar @ solución Doku-so de lo que es y tanto en este puesto y el puesto ligada nadie respondió el uso preguntas de error.

Entity Framework seguimiento de los cambios en los objetos que consultan la base de datos a través de DbContext. Por ejemplo, si DbContext nombre de instancia es dbContext

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

En ADO.NET Entity Framework Core 2.x no hay necesidad de Attach:

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

probado este en SQL Server y perfilado que:

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

Encuentra asegura que las entidades ya cargados no desencadenan un SELECT y también concede automáticamente la entidad si es necesario (de los documentos):

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

Yo uso ValueInjecter Nuget para inyectar enlace de modelos en base de datos usando Entidad siguiente:

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

Nota la utilización de la convención personalizada que no actualizar las propiedades si son nulos desde el servidor.

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

Uso:

target.InjectFrom<NoNullsInjection>(source);

Valor Injecter V2

esta respuesta

Advertencia

Usted no sabrá si la propiedad se borra intencionalmente a NULL o que simplemente no tienen ningún valor él. En otras palabras, el valor de la propiedad sólo puede ser sustituido por otro valor, pero sin despachar.

Yo estaba buscando misma y finalmente encontré la solución

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

créanme que funciona para mí como un encanto.

La combinación de varias sugerencias propongo lo siguiente:

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

llamado por

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

O por

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

O por

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();
  }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top