首页 > 解决方案 > .Include() EF Coe 的更新问题

问题描述

我一直在关注 有关在 EF 核心中处理并发冲突的ms 文档教程。我有两个模型:

电影.cs

public class Movie
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }

    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    [DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 300)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18,2)")]
    public decimal Price { get; set; }

    [Required]
    [StringLength(5)]
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    public string Rating { get; set; }

    public string Description { get; set; }

    [Timestamp]
    public byte[] ConcurrencyToken { get; set; }

    public int GenreId { get; set; }
    public Genre Genre { get; set; }

    public override string ToString()
    {
        return Title;
    }
}

流派.cs

public class Genre
{
    public Genre()
    {
        Movies = new List<Movie>();
    }

    [Key]
    public int GenreId { get; set; }
    
    [Required]
    [StringLength(30, MinimumLength = 5)]
    [Display(Name = "Genre Title")]
    [RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
    public string GenreTitle { get; set; }

    [Timestamp]
    public byte[] ConcurrencyToken { get; set; }

    [Display(Name = "Number of movies")]
    public ICollection<Movie> Movies { get; set; }

    public override string ToString()
    {
        return GenreTitle;
    }
}

当我尝试更新我的模型时,我遇到了一些奇怪的问题并且无法弄清楚为什么,没有抛出任何错误,模型只是没有得到更新。这是我的更新post方法:

public async Task<IActionResult> OnPostAsync(int? id)
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        // ConcurrencyToken may have changed.
        var movieToUpdate = await _context.Movie
            .Include(m => m.Genre)
            .FirstOrDefaultAsync(m => m.ID == id);

        if(movieToUpdate == null)
        {
            return HandleDeletedMovie();
        }

        // Set ConcurrencyToken to value read in OnGetAsync
        _context.Entry(movieToUpdate).Property(
            m => m.ConcurrencyToken).OriginalValue = Movie.ConcurrencyToken;

        if (await TryUpdateModelAsync<Movie>(
            movieToUpdate,
            "movie",
            m => m.Title, m => m.ReleaseDate,
            m => m.Price, m => m.Rating,
            m => m.GenreId))
        {
            try
            {
                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }
            catch(DbUpdateConcurrencyException ex)
            {
                var exceptionEntry = ex.Entries.Single();
                var clientValues = (Movie)exceptionEntry.Entity;
                var databaseEntry = exceptionEntry.GetDatabaseValues();

                if(databaseEntry == null)
                {
                    ModelState.AddModelError(string.Empty, "Unable to save. The movie was deleted by another user.");

                    return Page();
                }

                var dbValues = (Movie)databaseEntry.ToObject();
                await SetDbErrorMessage(dbValues, clientValues, _context);

                // Save the current ConcurrencyToken so next postback
                // matches unless an new concurrency issue happens.
                Movie.ConcurrencyToken = (byte[])dbValues.ConcurrencyToken;
                // Clear model error for the next postback
                ModelState.Remove($"{nameof(Movie)}.{nameof(Movie.ConcurrencyToken)}");
            }
        }

        // Get errors from TryUpdate
        var validationErrors = ModelState.Values.Where(E => E.Errors.Count > 0)
        .SelectMany(E => E.Errors)
        .Select(E => E.ErrorMessage)
        .ToList();

        PopelateGenresDropDownList(_context, movieToUpdate.Genre);
        return Page();
    }

在线更新失败TryUpdateModelAsync,并没有去try-catch。我发现导致问题的错误是对Include d in的Genre.GenreTitle属性进行验证。即使ModelState没有失败,它仍然会导致更新实体的错误。但是,当我检查Movie.Genre属性时完全没问题,应该没有任何错误。只有当我从中删除.Include时才有效。movievar movieToUpdate = await _context.Movie.FirstOrDefaultAsync(id)

现在,我想知道我的错误是什么,因为在文档中嵌套对象实际上是.Include d。

错误截图

标签: c#entity-framework-corerazor-pages

解决方案


我测试了你的正则表达式^[A-Z]+[a-zA-Z]*$,它似乎不接受空格字符。所以Genre Title不匹配表达式并触发错误。

您可以在 中添加空格[]来告诉表达式您还需要接受空格字符。我不知道它是否应该如何完成,但它适用于RegexStormRegex101(最后一个没有 c#,但我认为 Regex 有点通用)。


推荐阅读