2017-01-11 2 views
0

Wieder ...MVC Entity Framework Mapper zur Ansicht Modell zu aktualisieren Tabelle

Ich mache eine MVC mit EF5 App. Ich habe eine Benutzer-Entität, die EF mit Benutzer Tabelle in Datenbank bindet ... Sieht so aus.

public partial class Users 
{ 
    public long User_id { get; set; } 
    [Required] 
    [StringLength(30, ErrorMessage = "LastName cannot be longer than 30 characters.")] 
    public string LastName { get; set; } 
    [Required] 
    [StringLength(30, ErrorMessage = "Name cannot be longer than 30 characters.")] 
    public string Name { get; set; } 
    public int ProcessState_id { get; set; } 
    public string Sex { get; set; } 

    [Required,Range(1, int.MaxValue, ErrorMessage = "El País es Obligatorio")] 
    public int Country_id { get; set; } 

    [Required] 
    [EmailAddress(ErrorMessage = "Invalid Email Address")] 
    public string Email { get; set; } 
    public System.DateTime CreationDate { get; set; } 
    public Nullable<System.DateTime> UpDateTime { get; set; } 
    [RegularExpression(@"^.{5,}$", ErrorMessage = "Minimum 3 characters required")] 
    [Required] 
    [StringLength(9, MinimumLength = 3, ErrorMessage = "Password cannot be longer than 9 characters.")] 
    public string Password { get; set; } 
    public string Url { get; set; } 
    public byte[] Picture { get; set; } 
    public string CodArea { get; set; } 
    public string PhoneNumber { get; set; } 
    public virtual Countries Countries { get; set; } 
    public virtual ProcessStates ProcessStates { get; set; } 
    public virtual States States { get; set; } 
    [NotMapped] // Does not effect with your database 
    [RegularExpression(@"^.{5,}$", ErrorMessage = "Minimum 3 characters required")] 
    [StringLength(9, MinimumLength = 3, ErrorMessage = "Confirm Password cannot be longer than 9 characters.")] 
    [Compare("Password")] 
    public virtual string ConfirmPassword { get; set; } 
} 

Ich habe ein Modell der Klasse, dass ich es verwenden, in meiner Ansicht erstellen ....

public class UserViewModel 
{ 
    public Users user { get; set; } 
    public IList<SelectListItem> AvailableCountries { get; set; } 
} 

Mein Create-Methode im Controller eine bekommt UserViewModel Instanz ...

Mein erstellen Methode sieht so aus.

public async Task<ActionResult> Create(UserViewModel model, System.Web.HttpPostedFileBase image = null) 
{ 
    try 
    { 
     if (ModelState.IsValid) 
     { 
      model.user.ProcessState_id = Security.WAITING; 
      model.user.Rol_id = Security.ROL_PUBLIC; 
      model.user.CreationDate = DateTime.Now; 
      model.user.IP = Request.UserHostAddress; 
      model.user.Url = UserValidation.EncriptacionURL(model.user.Email); 
      if (image != null) 
      { 
       // product.ImageMimeType = image.ContentType; 
       model.user.Picture= new byte[image.ContentLength]; 
       image.InputStream.Read(model.user.Picture, 0, image.ContentLength); 
      } 
      _db.Users.Add(model.user); 
      _db.SaveChanges(); 
      return RedirectToAction("Create"); 
     } 
     model.AvailableCountries = GetCountries(); 
     return View(model); 
    } 
    catch (RetryLimitExceededException /* dex */) 
    { 
    } 
    return View(model); 
} 

So weit so gut.

Für meine Bearbeitungsansicht brauche ich weniger Eigenschaften von Benutzerklasse, also habe ich eine neue Klasse mit den Eigenschaften, die ich brauche. Diese Klasse heißt UserEditView.

public class UserEditView 
{ 
    public long User_id { get; set; } 
    [Required] 
    [StringLength(30, ErrorMessage = "LastName cannot be longer than 30 characters.")] 
    public string LastName { get; set; } 
    [Required] 
    [StringLength(30, ErrorMessage = "Name cannot be longer than 30 characters.")] 
    public string Name { get; set; } 
    [Required, Range(1, int.MaxValue, ErrorMessage = "El País es Obligatorio")] 
    public int Country_id { get; set; } 
    [Required] 
    [EmailAddress(ErrorMessage = "Invalid Email Address")] 
    public string Email { get; set; } 
    public Nullable<System.DateTime> UpDateTime { get; set; } 
    public byte[] Picture { get; set; } 
    public string CodArea { get; set; } 
    public string PhoneNumber { get; set; } 

    public virtual Countries Countries { get; set; } 
} 

Ich rief auch ein neues Modell für die Bearbeiten-Ansicht erstellen, UserEditViewModel und sieht wie folgt aus.

public class UserEditViewModel 
{ 
    public UserEditView user { get; set; } 
    public IList<SelectListItem> AvailableCountries { get; set; } 
} 

Auf meiner Methode bearbeiten, verwende ich Mapper mit User Unternehmen zu binden UserEditView

public ViewResult Edit(int User_id=3) 
{ 
    Users users = _db.Users 
    .FirstOrDefault(p => p.User_id == User_id); 

    var config = new MapperConfiguration(cfg => 
    { 
     cfg.CreateMap<Users, UserEditView>(); 
    }); 

    IMapper mapper = config.CreateMapper(); 
    UserEditView userEditView = mapper.Map<Users, UserEditView>(users); 

    var model = new UserEditViewModel 
    { 
     user = userEditView, 
     AvailableCountries = GetCountries(), 
    }; 

    return View(model); 
} 

Mein Problem entstehen, wenn ich die Benutzertabelle aktualisieren möchten.

Die Edit-Methode wird UserEditViewModel Instanz.

public async Task<ActionResult> Edit(UserEditViewModel model, System.Web.HttpPostedFileBase image = null) 
{ 
    try 
    { 
     if (ModelState.IsValid) 
     {} 
    } 
} 

UserEditViewModel hat eine Instanz von UserEditView aber ich brauche eine Instanz von Users um EF-Updates Benutzertabelle.

Ich muss erneut zuordnen? Wie kann ich eine Benutzerinstanz bekommen?

I Fügen Sie die folgende Klasse

public static class AutoMapperBootStrapper 
 
    { 
 
     public static void BootStrap() 
 
     { 
 
      var config = new MapperConfiguration(cfg => 
 
      { 
 
       cfg.CreateMap<Users, UserEditView>(); 
 
       cfg.CreateMap<UserEditView, Users>(); 
 
      }); 
 
      IMapper mapper = config.CreateMapper(); 
 

 
     }

Und ich hinzufügen in meinem Global.asax

public class MvcApplication : System.Web.HttpApplication 
 
    { 
 
     protected void Application_Start() 
 
     { 
 
      AutoMapperBootStrapper.BootStrap(); 
 
      AreaRegistration.RegisterAllAreas(); 
 
      RouteConfig.RegisterRoutes(RouteTable.Routes); 
 
      BundleConfig.RegisterBundles(BundleTable.Bundles); 
 
     } 
 
    }

dann in der Steuerung .. I.

public ViewResult Edit(int User_id=3) 
 
     { 
 
      Users users = _db.Users.FirstOrDefault(p => p.User_id == User_id); 
 

 
UserEditView userEditView = Mapper.Map<Users, UserEditView>(users); 
 
}

Aber Mapper.Map haben einen Fehler machen ... sagt es Mapper instanziiert wird nicht.

das Problem liegt daran, dass ich mehr als einen Mapper definiert.Wenn ich nur einen definiere, funktioniert es gut ...

Antwort

2

Ich muss wieder zuordnen? Wie kann ich eine Benutzerinstanz erhalten?

Sie konnten die User-Modell aus der Datenbank erhalten die ID verwenden und ordnen Sie die Eigenschaften, die Sie benötigen, aus der Sicht Modell aktualisiert werden:

[HttpPost] 
public ActionResult Edit(UserEditViewModel model, HttpPostedFileBase image = null) 
{ 
    if (!ModelState.IsValid) 
    { 
     // Validation failed => redisplay the Edit form so that the 
     // user can correct the errors 
     return View(model); 
    } 

    var user = _db.Users.FirstOrDefault(p => p.User_id == model.user.User_id); 
    if (user == null) 
    { 
     // no user with the specified id has been found in the database => 
     // there's nothing to update 
     return NotFound(); 
    } 

    // This will map only the properties of the user object that 
    // are part of the view model 
    Mapper.Map<Users, UserEditView>(model.user, user); 

    // at this stage you could manually update some properties that 
    // have not been mapped such as the uploaded image 

    // finally persist the changes to the database 
    _db.SaveChanges(); 

    // redirect to some other action to show the updated users 
    return RedirectToAction("users"); 
} 

Auch der Code, den Sie in Ihrer Frage gezeigt haben, :

var config = new MapperConfiguration(cfg => 
{ 
    cfg.CreateMap<Users, UserEditView>(); 
}); 

IMapper mapper = config.CreateMapper(); 

Das ist absolut NICHT etwas, das Sie in einer Controller-Aktion tun sollten. AutoMapper-Zuordnungen sollten nur einmal pro Anwendungslebensdauer konfiguriert werden, idealerweise beim Start der Anwendung, z. B. für eine Webanwendung, die in Global.asax Application_Start lautet. In einer Controller-Aktion sollten Sie nur die bereits konfigurierten Mappings verwenden. Ich empfehle dringend, dass Sie die AutoMapper-Dokumentation durchgehen, um ein besseres Verständnis für die Verwendung dieses Frameworks zu erhalten.

Zitat aus dem documentation:

Wo finde ich AutoMapper konfigurieren?

Wenn Sie die statische Mapper-Methode verwenden, sollte nur einmal pro AppDomain die Konfiguration passieren. Das bedeutet, dass der beste Konfigurationscode im Anwendungsstart ist, z. B. die Datei Global.asax für ASP.NET-Anwendungen. In der Regel befindet sich die Bootstrapper-Klasse in einer eigenen Klasse, und diese Bootstrapper-Klasse ist , die von der Startmethode aufgerufen wird. Die Bootstrapper-Klasse sollte Mapper.Initialize aufrufen, um die Typzuordnungen zu konfigurieren.

+0

IF I MapperConfiguration Global Asax, um Zugang 'IMapper Mapper' aus dem Regler zu definieren, habe ich es als Public zu definieren, und rufen UserEditView userEditView = mapper.Map (Benutzer); von 'Controller' ..? – Diego

+0

Sie können die statische Methode 'Mapper.Map ' wie in meiner Antwort gezeigt verwenden. Oder injizieren Sie die Mapper.Engine in Ihren Controller, wenn Sie eine bessere Abstraktion über die Mapping-Logik haben möchten. Dennoch sollte Ihre Zuordnungskonfiguration nur einmal pro Anwendungsdomäne erfolgen, d. H. In Ihrem Application_Start. –

+0

Es gibt mir einen Fehler .. es sagt, dass es instanziiert werden muss. – Diego