首页 > 解决方案 > EF Core - 更新实体

问题描述

我想通过实体框架核心产品实体更新数据库。

在每次加载一个产品时,我想增加一个访问次数。

产品上下文类:

[Table("product")]
public class Product
{
    [Key]
    [Column("id", TypeName = "int")]
    public int Id { get; set; }
    [Column("name")]
    public string Name { get; set; }
    [Column("active", TypeName = "bit")]
    public bool Active { get; set; }
    [Column("visited")]
    public int Visited { get; set; }

    // last group
    [Column("group_id")]
    public int GroupId { get; set; }
    [ForeignKey("GroupId")]
    public virtual Group Group { get; set; }

    // first group
    [Column("top_group_id")]
    public int? TopGroupId { get; set; }
    [ForeignKey("TopGroupId")]
    public virtual Group TopGroup { get; set; }

    // PN image
    [Column("file_image_id")]
    public int? ImageId { get; set; }

    [ForeignKey("ImageId")]
    public virtual File Image { get; set; }

    public virtual IEnumerable<ProductGrade> ProductGrades { get; set; }
    public virtual IEnumerable<ProductDescription> ProductDescriptions { get; set; }
    public virtual IEnumerable<ProductFile> ProductFiles { get; set; }
 }

在 Controller 中,我调用 CTOR _context:

// In class
private readonly ProductContext _context; 

// In method
var product = await _context.Products
                .OrderBy(b => b.Name)
                .Where(w => w.Name == model.Name)
                .Select(c => new ProductResDto
                {
                    Id = c.Id,
                    PartNumber = c.Name,
                    Group = c.Group.FullLink,
                    GroupId = c.GroupId,
                    Type = c.TopGroup.Name,
                    Image = new FileDto
                    {
                        Name = c.Image.Name,
                        GroupName = c.Image.FileGroup.Name,
                        Url = (c.Group.Top.Link != "/" ? c.Group.Top.Link : c.Group.Link) + "/pn/" + c.Image.Url,
                        Title = c.Image.Title,
                        Type = c.Image.FileType.MineType
                    }
                }).FirstAsync();

ProductResDto 类:

public class ProductResDto
{
    [JsonIgnore] public int Id { get; set; }
    public string PartNumber { get; set; }
    public string Type { get; set; }
    public string Group { get; set; }
    [JsonIgnore] public int GroupId { get; set; }
    public ICollection<ParameterValueDto> Parameters { get; set; }
    public ICollection<ProductValueDto> Descriptions { get; set; }
    public ICollection<ProductValueDto> Grades { get; set; }
    public ICollection<FileGroupDto> Files { get; set; }
    public FileDto Image { get; set; }
    public ICollection<BreadCrumbDto> BreadCrumbs { get; set; }
    public RelatedProductResDto RelatedProducts { get; set; }
}

我想简单地更新产品记录,例如:

var data = await _context.Products
            .OrderBy(b => b.Name)
            .Where(w => w.Name == model.Name && w.Active).FirstAsync();

        var product = new ProductResDto
        {
            Id = data.Id,
            PartNumber = data.Name,
            Group = data.Group.FullLink,
            GroupId = data.GroupId,
            Type = data.TopGroup.Name,
            Image = new FileDto
            {
                Name = data.Image.Name,
                GroupName = data.Image.FileGroup.Name,
                Url = (data.Group.Top.Link != "/" ? data.Group.Top.Link : data.Group.Link) + "/pn/" + data.Image.Url,
                Title = data.Image.Title,
                Type = data.Image.FileType.MineType
            }
        };

        data.Visited += 1;

        _context.Products.Update(data);
        await _context.SaveChangesAsync();

我只得到错误,因为变量数据只有原始数据 pro DB Product。有没有更好的方法可以更轻松地做到这一点?

就像在控制器中我将数据库上下文类产品及其所有依赖项分配给 ProductResDto 一样?

错误:

System.NullReferenceException:“对象引用未设置为对象的实例。”

var product = new ProductResDto在行中

在此处输入图像描述

它仅加载产品但没有引用,这是我要求的简单方法,例如在我使用的控制器中var product = await _context.Products

感谢您的任何帮助

标签: c#.netentity-framework-core

解决方案


您需要添加.Include()语句,因为没有它们,EF Core 将不会加载相关的属性GroupTopGroup并且Image(这称为延迟加载)并且正如您在图像中看到的那样,这些属性确实为空。

看起来您也在使用更深层次的嵌套属性,您可以使用.ThenInclude().

方法如下:

var data = await _context.Products
    .Include(p => p.Group).ThenInclude(g => g.Top)
    .Include(p => p.TopGroup)
    .Include(p => p.Image).ThenInclude(i => i.FileGroup)
    .Include(p => p.Image).ThenInclude(i => i.FileType)
    .OrderBy(b => b.Name)
    .Where(w => w.Name == model.Name && w.Active)
    .FirstAsync();

此示例可能尚未 100% 完成,在这种情况下,您需要添加更多.Include和/或.ThenInclude语句。

EF Core 始终分析完整的 LINQ 查询语句。由于.Select()第一个代码块中的语句中存在的内容,EF Core 会看到您需要嵌套属性,并且它将创建也加载这些属性的 SQL。但是如果没有.Select()给 EF Core 这个信息,那么你需要添加.Include()语句 + 可能还有.ThenInclude()语句。


推荐阅读