Поиск дубликатов объектов, которые уже существуют в базе данных

#c# #sql #.net #.net-core #entity-framework-core

#c# #sql #.net #.net-ядро #entity-framework-core

Вопрос:

У меня есть таблица базы данных с объектами. Объекты имеют PK и уникальный индекс с 4 свойствами. Что я хочу сделать, это добавить новый объект в БД и переместить дубликат «старого» объекта из другой таблицы, известной как «История».

Поэтому, когда я загружаю новый csv-файл, я хочу получить все существующие объекты в БД, которые являются дубликатами объектов в новом csv-файле.

Файлы csv могут быть большими и содержать более 10 тыс. объектов, поэтому требуется много времени, чтобы просмотреть их и проверить, существует ли индекс / идентификатор в базе данных.

Я пытался сохранить объекты с уникальным индексным ключом, но не знаю, как получить уже существующие объекты.

Скриншоты для справки:

Сущность

Родительский

Комментарии:

1. Заботитесь ли вы о производительности? Или просто нужно это через чистый EF?

2. Я действительно забочусь о производительности. Я использую ef, так как это единственное, что я знаю.

3. Что ж, я подготовлю образец со сторонним расширением EF Core. Какую базу данных вы используете?

4. Azure Sql Server

5. Также добавьте свой класс сущности. Проще всего будет показать, что делать.

Ответ №1:

Поскольку ядро EF не поддерживает массовые операции по соображениям производительности, лучше сделать это с помощью стороннего расширения (отказ от ответственности, я один из создателей) https://github.com/linq2db/linq2db.EntityFrameworkCore

Для быстрого чтения CSV я предлагаю эту библиотеку https://github.com/mgholam/fastCSV Он будет непрерывно загружать файл через IEnumerable, не используя много памяти.

Лучше реализовать такую вставку с помощью временной таблицы:

 var items = ... // you have read CSV file and created enumeration of objects, let's name them SomeItem
using var db = ctx.CreateLinqToDBConnection();
using var temp = db.CreateTempTable("#to_inject", items);

var queryToHistory = 
   from s in db.GetTable<SomeItem>()
   from t in temp.InnerJoin(t => t.key1 == s.Key1 amp;amp; t.Key2 == s.Key2 amp;amp; t.Key3 == s.Key3)
   select s;

using var tran = db.BeginTransaction();

// inserting into History table
queryToHistory.Insert(db.GetTable<SomeItemHistory>(), s => new SomeItemHistory 
  {
     Key1 = s.Key1,
     Key2 = s.Key2,
     Key3 = s.Key3,
     
     Value1 = s.Value1,
     Value2 = s.Value2,
     ...
  });

// inserting new records or update existing
db.GetTable<SomeItem>()
  .Merge()
  .Using(temp)
  .OnTargetKey()
  .InsertWhenNotMatched()
  .UpdateWhenMatched()
  .Merge();

tran.Commit();
 

Комментарии:

1. Это сработало хорошо! Но при создании «CreateTempTable». В нем говорится, что идентификатор должен быть числовым числом. Есть ли способ изменить это?

2. Ну, какая сущность? Какой тип Id в базе данных?

3. Лучше обновите ваш вопрос с помощью классов и DDL для таблиц.