Как избежать записи дубликатов в БД при использовании Entity FrameWork Core

В один момент из сторонних API наш сервис получает определённую информацию. Эту информацию нам необходимо сохранить у себя в БД. Однако возможна такая ситуация, что данные будут скачены повторно. Соответственно это либо запись новой информации с удалением старой (недопустимо в нашей ситуации), либо игнорирование дубликатов. На текущий момент для игнорирования дубликатов я вижу 2 пути:

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

Есть ли в Entity FrameWork Core менее закостыленный способ решения проблемы с дубликатами?


Ответы (2 шт):

Автор решения: Igor Ilyichyov

Я бы сделал так: перед тем как записать в таблицу проверил бы на уникальность по какому нибудь ид.

.Any(x=>x.Id == entity.Id)

Приблизительно вот так:

private bool CheckIfEntityRecordExists(Entity e)
{
    var retVal = false;
    using (var db = new EntityContext())
    {
        retVal = db.Clients.Count(a => a.Id == e.Id) > 0;
    }
    return retVal;
}
→ Ссылка
Автор решения: Anatoly

После правильно поставленного вопроса @IgorIlyichyov в комментариях к самому вопросу, решение в некоторой степени оказалось на поверхности. Насколько я понял, в самом Entity FrameWork Core подходящего решения не предусмотрено. Так что как вариант - использовать SQL: (для примера взяты страны)

    public async Task AddCountries()
    {
         List<Country> countries = new List<Country>() {
            new Country() { Alpha2 = "AB", EnName = "Republic Of Abkhazia" },
            new Country() { Alpha2 = "AD", EnName = "Andorra" } };

        string sqlCommand = "INSERT IGNORE INTO `Countries` (`Alpha2`, `EnName`) VALUES";

        for (int i = 0; i < countries.Count; i++)
        {
            sqlCommand += $" (\"{countries[i].Alpha2}\", \"{countries[i].EnName}\")";
            if (i == countries.Count - 1)
            {
                sqlCommand += ";";
            }
            else
            {
                sqlCommand += ",";
            }
        }

        var countOfChangedStrings = await _db.Database.ExecuteSqlRawAsync(sqlCommand);
     }


public class Country
{
    [Key]
    public string Alpha2 { get; set; }
    public string EnName { get; set; }
}

При таком подходе нужно быть аккуратным с SaveChanges() - он не требуется.

UPD: Как верно было подмечено в комментариях, такой подход сработает с MySQL, а вот с другими СУБД - не всегда

→ Ссылка