为了给您提供一些背景信息,我目前正在学习如何创建 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>
高度赞赏解决此问题或更好地理解我做错了什么的任何帮助或指导。非常感谢!
让我们对此进行分解,看看如何解决 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。
分步指南
以下是 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);
}
}
您的 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 属性。