C# 实体框架核心Put请求仅部分更新不会更新文件

C# 实体框架核心Put请求仅部分更新不会更新文件,c#,asp.net-core,entity-framework-core,C#,Asp.net Core,Entity Framework Core,问题:部分更新编辑数据不会更新编辑表单的文件部分 我正在使用ASP.NET Core和Entity Framework Core 5以及vue js前端。我确实从前端获取了所有数据,包括文件,但当它点击save方法时,它只保存基本数据,而不保存文件 这是我的请求 [HttpPut("{key:int}")] public async Task<IActionResult> PutAsset(int key,[FromForm] AssetPutDt

问题:部分更新编辑数据不会更新编辑表单的文件部分

我正在使用ASP.NET Core和Entity Framework Core 5以及vue js前端。我确实从前端获取了所有数据,包括文件,但当它点击save方法时,它只保存基本数据,而不保存文件

这是我的请求

    [HttpPut("{key:int}")]
    public async Task<IActionResult> PutAsset(int key,[FromForm] AssetPutDto assetPutDto)
    {
        IList<AssetFile> assetFiles = new List<AssetFile>();
        if (assetPutDto.Files == null)
            {
                assetFiles = null;
            }
            else
            {
                foreach (var file in assetPutDto.Files)
                {
                    if (file.Length <= 0) continue;
                    await using var ms = new MemoryStream();
                    await file.CopyToAsync(ms);
                    var fileBytes = ms.ToArray();

                    var thisFile = new AssetFile()
                    {
                        File = fileBytes,
                        Name = file.FileName,
                        MimeType = file.ContentType
                    };
                    assetFiles.Add(thisFile);
                }
            }

            assetPutDto.AssetFiles = assetFiles;
            var asset = _mapper.Map<Asset>(assetPutDto);
            asset.Id = key;
            
            _context.Entry(asset).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException dce)
            {
                if (!AssetExists(key))
                {
                    return NotFound();
                }
                else
                {
                    Console.WriteLine(dce.ToString());
                }
            }

        return NoContent();
    }
[HttpPut(“{key:int}”)]
公共异步任务PutAsset(int键,[FromForm]AssetPutTo AssetPutTo)
{
IList assetFiles=新列表();
if(assetPutDto.Files==null)
{
assetFiles=null;
}
其他的
{
foreach(assetPutDto.Files中的var文件)
{

如果(file.LengthEF Core通过在对象中表示数据来工作,但由于您的代码显示的对象并不总是与表记录的代码表示形式相同的类型,因此,为了使实体确认该对象是对您的记录的引用,必须正确设置键并“强制”告诉实体此对象已更改,现在必须通过
\u context.Entry(asset).State=EntityState.Modified;
更新它,但当您这样做时,此实体将只确认并跟踪资产对象,其所有关系将被忽略

太长,读不下去了
  • 首先让EF在对关系进行更改之前加载关系 使用
    \u context.Attach(asset);

  • 使用
    await\u context.Entry(asset).Collection(d=>d.Files.LoadAsync();

  • 对关系进行更改(使用automapper或事先手动保存上一个集合并在此处重置

  • 使用
    wait\u context.SaveChangedAsync()更新

  • 详细的 在您的情况下,EF不会更新其关系,因为它们没有被跟踪

    在这篇文章中,我做了一些测试,以确保这是正在发生的事情,而且确实如此

    首先运行迁移,然后运行
    InitialSeed()
    方法来为我们将要测试的数据播种

    如果运行
    caseproduction()
    ,它将再现代码中发生的事情,并向控制台提供有用的日志

    设置不计数;
    更新[资产]集合[名称]=@p0
    其中[Id]=@p1;
    选择@@ROWCOUNT;
    
    在此日志中,我们可以看到
    资产的属性正在更改,但是
    资产文件的属性没有任何变化

    但是,如果我们在进行更改之前让实体识别并加载其关系(通过运行
    CaseCorrection()
    方法),我们会看到实体将
    资产
    关系加载并确认到
    资产文件
    ,并使用以下日志相应地更新它们:

    设置不计数;
    从[资产文件]中删除
    其中[Id]=@p0;
    选择@@ROWCOUNT;
    从[资产文件]中删除
    其中[Id]=@p1;
    选择@@ROWCOUNT;
    从[资产文件]中删除
    其中[Id]=@p2;
    选择@@ROWCOUNT;
    从[资产文件]中删除
    其中[Id]=@p3;
    选择@@ROWCOUNT;
    从[资产文件]中删除
    其中[Id]=@p4;
    选择@@ROWCOUNT;
    插入到[AssetFile]([Id]、[AssetId]、[Name])
    数值(@p5、@p6、@p7),
    (@p8、@p9、@p10);
    更新[资产]集合[名称]=@p11
    其中[Id]=@p12;
    选择@@ROWCOUNT;
    

    PS:您也可以加载实体及其所有关系,而不是创建一个新对象并使用
    \u context.Assets.Include(asset=>asset.AssetFiles.FirstOrDefault(d=>d.Id==key)将其附加到数据库
    ,然后在使用或不使用自动映射器的情况下更改此对象

    是否确实,您的映射器对象正在将您的
    资产输出映射到.AssetFile
    ?在调用映射器.Map方法后设置断点,并确保您的资产文件映射正确。此外,如果资产文件数据正在另一个表中保存,我不确定是否将理解并替换以前保存的联接表data@Patrick查看映射器,它似乎正在映射文件,我的意思是我将资产一直映射到_context.Entry点,但之后什么都没有。如果ef core不了解如何获取资产以更新表a,那么资产文件确实保存在它们自己的表中像资产表一样膨胀?您可以通过“急切”或“懒散”加载资产实体及其导航属性,然后手动删除并插入新的资产文件。请您提供一个示例,说明我如何做到这一点。我对ef core仍然是新手,并且仍然了解我需要做什么……thanksI将提供一个答案,是jus吗t测试以确保我传递了正确的信息,而不仅仅是你如何解决这个问题谢谢你在这方面的帮助,
        public class AssetPutDto : AssetDto
        {
                /// <summary>
               /// Sets the files to Iformfile format to process it to the database
              /// </summary>
              public IList<IFormFile> Files { get; set; }
              // TODO: RetireDate
             // Gets and sets the AssetFiles property
             public IList<AssetFile> AssetFiles { get; set; }
        }