英文:
TryUpdateModelAsync rejects null naviagation properties?
问题
TryUpdateModelAsync()
似乎会拒绝我的模型对象,如果导航属性为空,即使外键已正确设置。
例如,如果AuthorId
已设置但Author
为空,它将不会接受一个Book
对象:
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public int AuthorId { get; set; }
public Author Author { get; set; }
}
以下是一个完整的工作示例,显示了这种行为的问题:
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public List<Book> Books { get; set; }
}
模型:
public class EditModel : PageModel
{
private readonly YourDbContext _context;
private readonly ILogger<EditModel> _logger;
[BindProperty] public Book Book { get; set; }
public List<Author> Authors { get; set; }
public EditModel(YourDbContext context, ILogger<EditModel> logger)
{
_context = context;
_logger = logger;
}
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null) { return NotFound(); }
Book = await _context.Books.Include(b => b.Author).FirstOrDefaultAsync(m => m.Id == id);
if (Book == null) { return NotFound(); }
Authors = await _context.Authors.ToListAsync();
return Page();
}
public async Task<IActionResult> OnPostAsync(int? id)
{
var bookToUpdate = await _context.Books.FindAsync(id);
if (bookToUpdate == null) { return NotFound(); }
if (await TryUpdateModelAsync<Book>(bookToUpdate, "book", b => b.Title, b => b.AuthorId))
{
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
else
{
foreach (var modelStateKey in ModelState.Keys)
{
var modelStateVal = ModelState[modelStateKey];
foreach (var error in modelStateVal.Errors)
{
_logger.LogError($"Key: {modelStateKey}, Error: {error.ErrorMessage}");
}
}
}
Book = bookToUpdate;
return RedirectToPage(new { id });
}
}
Razor Page:
@page
@model EditModel
<form method="post">
<input type="hidden" asp-for="Book.Id" />
<input asp-for="Book.Title" />
<select asp-for="Book.AuthorId" asp-items="@(new SelectList(Model.Authors, "Id", "Name"))"></select>
<input type="submit" value="Save" />
</form>
模型状态将始终包含以下错误:
Key: Book.Author, Error: The Author field is required.
这显然是一个简化的示例,但通常可能有许多大型导航属性,因此无法填充它们。
英文:
TryUpdateModelAsync()
seems to reject my model objects if the navigation property is null, even though the foreign key is properly set.
For example, it won't accept a Book if AuthorId is set, but Author is null:
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public int AuthorId { get; set; }
public Author Author { get; set; }
}
Here is a complete working example showing the problem of this behavior:
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public List<Book> Books { get; set; }
}
Model:
public class EditModel : PageModel
{
private readonly YourDbContext _context;
private readonly ILogger<EditModel> _logger;
[BindProperty] public Book Book { get; set; }
public List<Author> Authors {get; set;}
public EditModel(YourDbContext context, ILogger<EditModel> logger)
{
_context = context;
_logger = logger;
}
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null) { return NotFound(); }
Book = await _context.Books.Include(b => b.Author).FirstOrDefaultAsync(m => m.Id == id);
if (Book == null) { return NotFound(); }
Authors = await _context.Authors.ToListAsync();
return Page();
}
public async Task<IActionResult> OnPostAsync(int? id)
{
var bookToUpdate = await _context.Books.FindAsync(id);
if (bookToUpdate == null) { return NotFound(); }
if (await TryUpdateModelAsync<Book>(bookToUpdate, "book", b => b.Title, b => b.AuthorId))
{
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
else
{
foreach (var modelStateKey in ModelState.Keys)
{
var modelStateVal = ModelState[modelStateKey];
foreach (var error in modelStateVal.Errors)
{
_logger.LogError($"Key: {modelStateKey}, Error: {error.ErrorMessage}");
}
}
}
Book = bookToUpdate;
return RedirectToPage(new { id});
}
}
Razor Page:
@page
@model EditModel
<form method="post">
<input type="hidden" asp-for="Book.Id" />
<input asp-for="Book.Title" />
<select asp-for="Book.AuthorId" asp-items="@(new SelectList(Model.Authors,"Id","Name"))"></select>
<input type="submit" value="Save" />
</form>
The modelstate will always have errors complaining:
Key: Book.Author, Error: The Author field is required.
This is obviously a simplified example, but in general there can be many large navigation properties, and so populating them all is not feasible.
答案1
得分: 1
在 .Net 6 或更高版本中,它会自动在您的 csproj 文件中启用可空引用类型:
<Nullable>enable</Nullable>
属性
public Author Author { get; set; }
将被视为非可空
正如在文档中提到的:
验证系统会将非可空参数或绑定属性视为具有 [Required(AllowEmptyStrings = true)] 特性。
如果要保持其为非可空,对于 MVC 项目的解决方案如下:
builder.Services.AddControllers(
options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);
在 Razor Page 项目中,您可以尝试:
builder.Services.Configure<MvcOptions>(x => x.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);
英文:
In .Net 6 or higher versions, it would enable nullable reference types atuomaticlly in your csproj file:
<Nullable>enable</Nullable>
The property
public Author Author { get; set; }
would be considered as non-nullable
And as mentioned in the document:
> The validation system treats non-nullable parameters or bound
> properties as if they had a [Required(AllowEmptyStrings = true)]
> attribute.
If you want to keep it as non-nullable,the solution for MVC projects:
builder.Services.AddControllers(
options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);
In Razor Page projects,you could try:
builder.Services.Configure<MvcOptions>(x=>x.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes=true);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论