#c# #asp.net-core #entity-framework-core
Вопрос:
Проблема: Частичное обновление данных редактирования не приведет к обновлению части файлов формы редактирования.
Я использую ASP.NET Ядро с ядром Entity Framework 5 с интерфейсом vue js. Я действительно получаю все данные с внешнего интерфейса, включая файлы, но когда он переходит к методу сохранения, он сохраняет только основные данные, а не файлы.
это мой запрос на размещение
[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();
}
и это мой актив, входящий в
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; }
}
Результат, который я ищу, заключается в том, что я хочу обновить данные, включая файлы. На данный момент я просто озадачен тем, почему это работает не так, как должно.
любая помощь в правильном направлении будет признательна
Комментарии:
1. Вы уверены, что ваш объект _mapper отображает ваш
assetPutDto.AssetFiles
? установите точку останова после _mapper. Вызов метода сопоставления и убедитесь, что ваши файлы активов правильно сопоставлены. Кроме того, если данные AssetFiles сохраняются в другой таблице, я не уверен, что ef поймет и заменит ранее сохраненные данные объединенной таблицы2. @Патрик взглянул на картограф, и, похоже, он сопоставляет файлы, я имею в виду, что я получаю ресурс полностью до _context. Точка входа, но после этого ничего. Файлы активов действительно сохраняются в их собственной таблице, если ef core не понимает этого, как я могу заставить его обновить эту таблицу так же, как и таблицу активов ?
3. вы можете загрузить объект актива с его свойством навигации либо путем нетерпеливой, либо ленивой загрузки, затем вручную удалить и вставить новые файлы активов
4. не могли бы вы помочь с примером того, как я могу это сделать, я все еще новичок в ef core и все еще понимаю, что мне нужно делать … Спасибо
5. Я дам ответ, я просто проверяю ситуацию, чтобы убедиться, что я передаю правильную информацию, а не только то, как вы решаете эту проблему
Ответ №1:
Эф ядро произведения, представляющие свои данные в объекты, а как шоу-код не всегда является объект того же типа, представительство код записи в таблице будут знать в лицо, поэтому для того, чтобы лицо признать объект в качестве ссылки к записи ключ должен быть грамотно расположен, и вы «насильственно» говорит лицо, к которому данный объект был изменен, и теперь она должна обновлять его через accordling _context.Entry(asset).State = EntityState.Modified;
но как вы делаете это существо лишь знание и отслеживание активов объекта и всех его отношений будут игнорироваться.
TL;DR
- заставьте EF загрузить отношения, прежде чем вносить в них изменения, сначала прикрепив объект к контексту с помощью
_context.Attach(asset);
- загрузка предыдущей связи из базы данных с
await _context.Entry(asset).Collection(d => d.Files).LoadAsync();
- внесение изменений в отношения (либо с помощью вашего автомата, либо вручную, предварительно сохранив предыдущую коллекцию и сбросив ее здесь
- обновление с помощью
await _context.SaveChangedAsync()
Подробный
в вашем случае EF не обновляет свои отношения, потому что они не отслеживаются
в этом репозитории я провел несколько тестов, чтобы быть действительно уверенным, что это то, что происходит, и это действительно так.
Запустите миграции, а затем
InitialSeed()
сначала выполните метод для заполнения данных, которые мы будем тестировать
если вы запустите CaseReproduction()
его, он воспроизведет то, что происходит в вашем коде, и предоставит консоли полезные журналы
SET NOCOUNT ON;
UPDATE [Assets] SET [Name] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;
в этом журнале мы видим, что свойства объекта asset
изменяются, но в нем ничего не говорится о assetfiles
но если мы заставим сущность распознать и загрузить ее связь до внесения изменений (методом запуска CaseCorrection()
), мы увидим, что сущность загружает и подтверждает asset
связь с assetfiles
ними и соответствующим образом обновляет их с помощью следующего журнала:
SET NOCOUNT ON;
DELETE FROM [AssetFiles]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;
DELETE FROM [AssetFiles]
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;
DELETE FROM [AssetFiles]
WHERE [Id] = @p2;
SELECT @@ROWCOUNT;
DELETE FROM [AssetFiles]
WHERE [Id] = @p3;
SELECT @@ROWCOUNT;
DELETE FROM [AssetFiles]
WHERE [Id] = @p4;
SELECT @@ROWCOUNT;
INSERT INTO [AssetFiles] ([Id], [AssetId], [Name])
VALUES (@p5, @p6, @p7),
(@p8, @p9, @p10);
UPDATE [Assets] SET [Name] = @p11
WHERE [Id] = @p12;
SELECT @@ROWCOUNT;
PS: вы также можете загрузить свою сущность со всеми ее отношениями вместо того, чтобы создавать новый объект и присоединять его к своей базе данных с _context.Assets.Include(asset => asset.AssetFiles).FirstOrDefault(d=> d.Id == key);
помощью, а затем изменять этот объект с помощью или без вашего автомата
Комментарии:
1. Спасибо вам за вашу помощь в этом,