Quiero actualizar una tabla de base de datos. El controlador recibe un modelo de vista con los datos apropiados. Si asigno cada variable miembro como en el ejemplo a continuación, funciona

[HttpPost]
public ActionResult Edit(Admin_vm vm) {
    var result = (from Users in db.Users
                              where Users.ID == usrID
                              select Users
                  ).FirstOrDefault();

    result.CompanyName = vm.ModifyUser.CompanyName;
    //this is where I would assign every single member variable
    db.SaveChanges();
    return View(vm);
}

Sin embargo, me pregunto si hay una manera de asignar directamente el objeto del modelo de vista de esta manera:

result = vm.ModifyUser;

Esto no me da un error, pero no asigna las variables miembro. ¿Hay una forma fácil de hacer esto?

¡Gracias!

0
mneumann 18 oct. 2017 a las 16:14

3 respuestas

La mejor respuesta

No puede establecer directamente su objeto de modelo de vista en su objeto de entidad de base de datos porque son objetos de clase diferente.

En cambio, puede asignar cada propiedad, esto se puede hacer manualmente (como lo está haciendo ahora), usando la reflexión o las bibliotecas existentes como ValueInjecter o AutoMapper.

Si ambos objetos son muy similares y tienen los mismos nombres de propiedad, usaría ValueInjecter ya que es muy rápido y fácil de usar, AutoMapper es mucho más lento pero permite mapeos más complejos (tuve serios problemas de rendimiento pero elegí el que sea mejor) se adapta a su escenario, es decir, velocidad vs flexibilidad).

Aquí le mostramos cómo hacerlo con ValueInjecter para el ejemplo en su pregunta:

Agregue el ValueInjecter NuGet:

Install-Package ValueInjecter -Version 3.1.1.5

Incluya el espacio de nombres en su clase de controlador:

using Omu.ValueInjecter;

Y luego en tu acción:

[HttpPost]
public ActionResult Edit(Admin_vm vm) {
    var result = (from Users in db.Users
                              where Users.ID == usrID
                              select Users
                  ).FirstOrDefault();

    result.InjectFrom(vm.ModifyUser);

    context.SaveChanges();

    return View(vm);
}

Para el método Crear, primero debe crear su objeto:

User user = new User();
user.InjectFrom(vm.ModifyUser);
1
Isma 18 oct. 2017 a las 13:44

Una posible solución es utilizar AutoMapper, que asignará automáticamente las propiedades de un objeto a otro siempre que las propiedades se nombren y escriban de la misma manera. Por lo tanto, puede hacer algo como esto dependiendo de los nombres de propiedad en su clase (también puede definir mapas personalizados si sus propiedades se nombran de manera diferente):

//create the map, this is normally done in a config file but can be done in many different places
Mapper.Initialize(x =>
{
        x.CreateMap<User, type of vm.ModifyUser goes here>().ReverseMap();
}

//map the vm to the user, this will update all fields on result to what is contained in vm.ModifyUser assuming properties are named and typed the same.
....db query to retrieve result... 
result = Mapper.Map<User>(vm.ModifyUser);
context.SaveChanges()

Puede agregar AutoMapper a través del Administrador de paquetes NuGet. Esta es una herramienta ampliamente utilizada que está bien documentada.

2
GregH 18 oct. 2017 a las 13:26

Parece que la carpeta modelo no funciona como esperabas. Es posible que deba escribir un cuaderno de modelo personalizado. El siguiente ejemplo fue extraído de aquí. Este ejemplo hereda de DefaultModelBinder y luego usa la reflexión para ONLY anular los enlaces cuando es del especificado escriba (HomePageModels en el ejemplo a continuación, pero sería su ViewModel u objetos ViewModel específicos, es decir, Admin_vm o ModifyUser). Para todo lo demás, se une normalmente, lo que probablemente se prefiere.

public class HomeCustomDataBinder : DefaultModelBinder
    {

        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(HomePageModels))
            {
                HttpRequestBase request = controllerContext.HttpContext.Request;

                string title = request.Form.Get("Title");
                string day = request.Form.Get("Day");
                string month = request.Form.Get("Month");
                string year = request.Form.Get("Year");

                return new HomePageModels
                {
                    Title = title,
                    Date = day + "/" + month + "/" + year
                };

                //// call the default model binder this new binding context
                //return base.BindModel(controllerContext, newBindingContext);
            }
            else
            {
                return base.BindModel(controllerContext, bindingContext);
            }
        }

    } 
0
Gary B 18 oct. 2017 a las 13:31