如何创建一个在 Razor 中处理视图模型的控制器?

问题描述 投票:0回答:1

为了给您提供一些背景信息,我目前正在学习如何创建 ASP.NET Core MVC 应用程序,但我无法弄清楚控制器的实际工作方式以及 EF 如何处理关系。

现在我有这两张表:

public class Persona
{
    public int Id { get; set; }
    public string Nombre { get; set; }
    public string ApellidoPaterno { get; set; }
    public string ApellidoMaterno { get; set; }
    public string Email { get; set; }
    public string Telefono { get; set; }

    // Relationship
    public int? UsuarioId { get; set; }
    public Usuario? Usuario { get; set; }  
}

public class Usuario
{
    public int Id { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    
    // Relacion
    public int? PersonaId { get; set; }
    [ForeignKey("PersonaId")]
    public Persona? Persona { get; set; }
}

这两个表具有一对一的关系,我创建了一个视图模型,用于同时显示和编辑它们。

这是我创建的视图模型:

public class PersonaUsuarioVista
{
        // Persona properties
        public string Nombre { get; set; }
        public string ApellidoPaterno { get; set; }
        public string ApellidoMaterno { get; set; }
        public string Email { get; set; }
        public string Telefono { get; set; }

        // Usuario properties
        public string Username { get; set; }
        public string Password { get; set; }
}

这是我用来正确显示和创建新的

Personas
Usuarios
的视图模型。

但是说到编辑。我不确定为什么它不起作用。

Get
方法工作正常,这意味着它确实在输入字段内显示数据。

但是一旦进行了更改并保存...我不知道为什么会出现这种情况。

这是编辑的

Post
方法:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, UsuarioPersonaVista.PersonaUsuarioVista model)
{
    if (ModelState.IsValid)
    {
        var personaToUpdate = await _context.Personas.FindAsync(id);

        if (personaToUpdate == null)
        {
            return NotFound();
        }

        var usuarioToUpdate = await _context.Usuarios.FirstOrDefaultAsync(u => u.PersonaId == id);

        if (usuarioToUpdate == null)
        {
            return NotFound();
        }

        // Update Persona properties
        personaToUpdate.Nombre = model.Nombre;
        personaToUpdate.ApellidoPaterno = model.ApellidoPaterno;
        personaToUpdate.ApellidoMaterno = model.ApellidoMaterno;
        personaToUpdate.Email = model.Email;
        personaToUpdate.Telefono = model.Telefono;

        // Update Usuario properties
        usuarioToUpdate.Username = model.Username;

        // Save changes
        _context.Usuarios.Update(usuarioToUpdate);
        _context.Personas.Update(personaToUpdate);
        await _context.SaveChangesAsync();

        return RedirectToAction(nameof(Index));
    }

    return View(model); // Return the view with the model if the ModelState is invalid
}

这是 Razor 页面本身:

<form asp-controller="Persona" asp-action="Edit" method="post">
    <div>
        <label for="Nombre">Nombre</label>
        <input type="text" asp-for="Nombre" />
        <span asp-validation-for="Nombre"></span>
    </div>
    <div>
        <label for="ApellidoPaterno">Apellido Paterno</label>
        <input type="text" asp-for="ApellidoPaterno" />
        <span asp-validation-for="ApellidoPaterno"></span>
    </div>
    <div>
        <label for="ApellidoMaterno">Apellido Materno</label>
        <input type="text" asp-for="ApellidoMaterno" />
        <span asp-validation-for="ApellidoMaterno"></span>
    </div>
    <div>
        <label for="Email">Email</label>
        <input type="text" asp-for="Email" />
        <span asp-validation-for="Email"></span>
    </div>
    <div>
        <label for="Telefono">Telefono</label>
        <input type="text" asp-for="Telefono" />
        <span asp-validation-for="Telefono"></span>
    </div>
    <div>
        <label for="Username">Username</label>
        <input type="text" asp-for="Username" />
        <span asp-validation-for="Username"></span>
    </div>
    <input type="submit" value="Editar">
</form>

高度赞赏解决此问题或更好地理解我做错了什么的任何帮助或指导。非常感谢!

c# asp.net-core asp.net-core-mvc razor-pages
1个回答
0
投票

让我们对此进行分解,看看如何解决 MVC .NET Core 应用程序中的 Edit 方法的问题。

了解控制器和 EF Core 的关系 首先,让我们确保了解实体框架 (EF) 如何处理关系以及控制器如何在此上下文中工作。

实体框架关系 在 EF Core 中,实体之间的关系是使用导航属性和外键定义的。在您的情况下,Persona 和 Usuario 类具有一对一的关系:

Persona 有一个 Usuario 的外键 (UsuarioId)。

Usuario 有一个 Persona 的外键(PersonaId)。

查看模型 PersonaUsuarioVista 视图模型结合了 Persona 和 Usuario 的属性以用于显示和编辑目的。

编辑方法中的问题 您提到,虽然 Get 方法可以正常工作,但 Post 方法不会按预期更新记录。让我们分解一下您的 Post 方法:

csharp
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, UsuarioPersonaVista.PersonaUsuarioVista model)
{
    if (ModelState.IsValid)
    {
        var personaToUpdate = await _context.Personas.FindAsync(id);
        if (personaToUpdate == null)
        {
            return NotFound();
        }

        var usuarioToUpdate = await _context.Usuarios.FirstOrDefaultAsync(u => u.PersonaId == id);
        if (usuarioToUpdate == null)
        {
            return NotFound();
        }

        // Update Persona properties
        personaToUpdate.Nombre = model.Nombre;
        personaToUpdate.ApellidoPaterno = model.ApellidoPaterno;
        personaToUpdate.ApellidoMaterno = model.ApellidoMaterno;
        personaToUpdate.Email = model.Email;
        personaToUpdate.Telefono = model.Telefono;

        // Update Usuario properties
        usuarioToUpdate.Username = model.Username;

        // Save changes
        _context.Usuarios.Update(usuarioToUpdate);
        _context.Personas.Update(personaToUpdate);
        await _context.SaveChangesAsync();

        return RedirectToAction(nameof(Index));
    }

    return View(model);
}

潜在问题 外键关系:

确保Persona和Usuario之间的关系配置正确。

更新相关实体时,请确保外键值设置正确。

跟踪更改:

EF Core 跟踪实体的更改。确保检索到的实体(personaToUpdate 和 usuarioToUpdate)与正在更新和保存的实例相同。

密码更新:

如果您不更新密码,请确保在更新过程中密码没有被清除。

建议更改 在 ViewModel 中包含密码(如果需要):

csharp
public class PersonaUsuarioVista
{
    // Persona properties
    public string Nombre { get; set; }
    public string ApellidoPaterno { get; set; }
    public string ApellidoMaterno { get; set; }
    public string Email { get; set; }
    public string Telefono { get; set; }

    // Usuario properties
    public string Username { get; set; }
    public string Password { get; set; } // Include this if the password needs updating
}
Ensure Changes are Tracked Properly:

csharp
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, UsuarioPersonaVista.PersonaUsuarioVista model)
{
    if (ModelState.IsValid)
    {
        var personaToUpdate = await _context.Personas.FindAsync(id);
        if (personaToUpdate == null)
        {
            return NotFound();
        }

        var usuarioToUpdate = await _context.Usuarios.FirstOrDefaultAsync(u => u.PersonaId == id);
        if (usuarioToUpdate == null)
        {
            return NotFound();
        }

        // Update Persona properties
        personaToUpdate.Nombre = model.Nombre;
        personaToUpdate.ApellidoPaterno = model.ApellidoPaterno;
        personaToUpdate.ApellidoMaterno = model.ApellidoMaterno;
        personaToUpdate.Email = model.Email;
        personaToUpdate.Telefono = model.Telefono;

        // Update Usuario properties
        usuarioToUpdate.Username = model.Username;
        if (!string.IsNullOrWhiteSpace(model.Password))
        {
            usuarioToUpdate.Password = model.Password; // Only update if Password is provided
        }

        // Save changes
        _context.Entry(personaToUpdate).State = EntityState.Modified;
        _context.Entry(usuarioToUpdate).State = EntityState.Modified;
        await _context.SaveChangesAsync();

        return RedirectToAction(nameof(Index));
    }

    return View(model);
}

Razor页面调整 确保 Razor 页面包含 Id 的隐藏字段:

html
<form asp-controller="Persona" asp-action="Edit" method="post">
    <input type="hidden" asp-for="Id" />
    <div>
        <label for="Nombre">Nombre</label>
        <input type="text" asp-for="Nombre" />
        <span asp-validation-for="Nombre"></span>
    </div>
    <div>
        <label for="ApellidoPaterno">Apellido Paterno</label>
        <input type="text" asp-for="ApellidoPaterno" />
        <span asp-validation-for="ApellidoPaterno"></span>
    </div>
    <div>
        <label for="ApellidoMaterno">Apellido Materno</label>
        <input type="text" asp-for="ApellidoMaterno" />
        <span asp-validation-for="ApellidoMaterno"></span>
    </div>
    <div>
        <label for="Email">Email</label>
        <input type="text" asp-for="Email" />
        <span asp-validation-for="Email"></span>
    </div>
    <div>
        <label for="Telefono">Telefono</label>
        <input type="text" asp-for="Telefono" />
        <span asp-validation-for="Telefono"></span>
    </div>
    <div>
        <label for="Username">Username</label>
        <input type="text" asp-for="Username" />
        <span asp-validation-for="Username"></span>
    </div>
    <div>
        <label for="Password">Password</label>
        <input type="password" asp-for="Password" />
        <span asp-validation-for="Password"></span>
    </div>
    <input type="submit" value="Editar">
</form>
Summary

总结起来,主要有以下几点:

确保将实体的状态设置为EntityState.Modified。

确保正确处理密码字段。

在表单中包含 Id 的隐藏字段。

太棒了,让我们在讨论的基础上创建一个控制器来处理 Razor 中的 PersonaUsuarioVista ViewModel。

分步指南

  1. 创建控制器 首先,让我们创建一个控制器。在您的项目中,您可以通过右键单击控制器文件夹并选择“添加”->“新项目...”->“控制器”来添加新控制器。将其命名为 PersonaController。

以下是 PersonaController 的外观示例:

csharp
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using YourNamespace.Models;
using YourNamespace.ViewModels;

public class PersonaController : Controller
{
    private readonly YourDbContext _context;

    public PersonaController(YourDbContext context)
    {
        _context = context;
    }

    // GET: Persona/Edit/5
    public async Task<IActionResult> Edit(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }

        var persona = await _context.Personas
            .Include(p => p.Usuario)
            .FirstOrDefaultAsync(m => m.Id == id);

        if (persona == null)
        {
            return NotFound();
        }

        var viewModel = new PersonaUsuarioVista
        {
            Nombre = persona.Nombre,
            ApellidoPaterno = persona.ApellidoPaterno,
            ApellidoMaterno = persona.ApellidoMaterno,
            Email = persona.Email,
            Telefono = persona.Telefono,
            Username = persona.Usuario?.Username
            // Password is not included here for security reasons, handle password updates separately
        };

        return View(viewModel);
    }

    // POST: Persona/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, PersonaUsuarioVista model)
    {
        if (id != model.Id)
        {
            return NotFound();
        }

        if (ModelState.IsValid)
        {
            var personaToUpdate = await _context.Personas.FindAsync(id);
            if (personaToUpdate == null)
            {
                return NotFound();
            }

            var usuarioToUpdate = await _context.Usuarios.FirstOrDefaultAsync(u => u.PersonaId == id);
            if (usuarioToUpdate == null)
            {
                return NotFound();
            }

            // Update Persona properties
            personaToUpdate.Nombre = model.Nombre;
            personaToUpdate.ApellidoPaterno = model.ApellidoPaterno;
            personaToUpdate.ApellidoMaterno = model.ApellidoMaterno;
            personaToUpdate.Email = model.Email;
            personaToUpdate.Telefono = model.Telefono;

            // Update Usuario properties
            usuarioToUpdate.Username = model.Username;
            if (!string.IsNullOrWhiteSpace(model.Password))
            {
                usuarioToUpdate.Password = model.Password; // Ensure password update is secure
            }

            try
            {
                _context.Update(personaToUpdate);
                _context.Update(usuarioToUpdate);
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!PersonaExists(personaToUpdate.Id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return RedirectToAction(nameof(Index));
        }

        return View(model);
    }

    private bool PersonaExists(int id)
    {
        return _context.Personas.Any(e => e.Id == id);
    }
}
  1. 创建视图 接下来,为“编辑”操作创建 Razor 视图。右键单击 Views 文件夹,然后添加一个名为 Persona 的新文件夹。在此文件夹中,添加一个名为 Edit.cshtml 的新 Razor 视图。

您的 Edit.cshtml 可能如下所示:

html
@model YourNamespace.ViewModels.PersonaUsuarioVista

<h2>Edit Persona and Usuario</h2>

<form asp-action="Edit">
    <input type="hidden" asp-for="Id" />
    <div>
        <label asp-for="Nombre"></label>
        <input asp-for="Nombre" class="form-control" />
        <span asp-validation-for="Nombre" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="ApellidoPaterno"></label>
        <input asp-for="ApellidoPaterno" class="form-control" />
        <span asp-validation-for="ApellidoPaterno" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="ApellidoMaterno"></label>
        <input asp-for="ApellidoMaterno" class="form-control" />
        <span asp-validation-for="ApellidoMaterno" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="Email"></label>
        <input asp-for="Email" class="form-control" />
        <span asp-validation-for="Email" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="Telefono"></label>
        <input asp-for="Telefono" class="form-control" />
        <span asp-validation-for="Telefono" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="Username"></label>
        <input asp-for="Username" class="form-control" />
        <span asp-validation-for="Username" class="text-danger"></span>
    </div>
    <div>
        <label asp-for="Password"></label>
        <input asp-for="Password" class="form-control" />
        <span asp-validation-for="Password" class="text-danger"></span>
    </div>
    <div>
        <input type="submit" value="Save" class="btn btn-primary" />
    </div>
</form>

<div>
    <a asp-action="Index">Back to List</a>
</div>
Summary

控制器:我们使用编辑操作创建了 PersonaController 来处理 GET 和 POST 请求。

视图:Razor 视图 Edit.cshtml 使用 PersonaUsuarioVista ViewModel 来显示和编辑 Persona 和 Usuario 属性。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.