Как избежать записи дубликатов в БД при использовании Entity FrameWork Core
В один момент из сторонних API наш сервис получает определённую информацию. Эту информацию нам необходимо сохранить у себя в БД. Однако возможна такая ситуация, что данные будут скачены повторно. Соответственно это либо запись новой информации с удалением старой (недопустимо в нашей ситуации), либо игнорирование дубликатов. На текущий момент для игнорирования дубликатов я вижу 2 пути:
- Перед внесением изменений в БД взять все существующие данные, и сравнивать их. Данный подход мне не нравится тем, что нужно обрабатывать все имеющиеся записи - это означает, что будет скушано много оперативки зазря.
- Добавлять каждую запись поштучно, затем на каждую запись вызывать
SaveChanges- если будет встречен дубликат, то будет брошено исключение. Данный подход не нравится тем, что это займёт много времени на то, чтобы каждый раз обращаться к БД.
Есть ли в Entity FrameWork Core менее закостыленный способ решения проблемы с дубликатами?
Ответы (2 шт):
Я бы сделал так: перед тем как записать в таблицу проверил бы на уникальность по какому нибудь ид.
.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;
}
После правильно поставленного вопроса @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, а вот с другими СУБД - не всегда