#c# #generics #entity-framework-core
#c# #универсальные #entity-framework-core
Вопрос:
У меня есть этот пример кода (.NET Core 2.2):
private void IterateSave(List<TokenMaster> items, int min, int max)
{
int skip = min;
int take = max / 5;
while (skip <= max)
{
try
{
var subItems = items.Skip(skip).Take(take).ToList();
_db.TokenMasters.AddRange(subItems); // <---
_db.SaveChanges();
skip = take;
}
catch (Exception ex)
{
Log.Error(ex, "Error saving this data batch! {RecordCount}", take);
IterateSave(items, skip, take);
}
}
}
private void IterateSave(List<Attributes> items, int min, int max)
{
int skip = min;
int take = max / 5;
while (skip <= max)
{
try
{
var subItems = items.Skip(skip).Take(take).ToList();
_db.Attributes.AddRange(subItems); // <---
_db.SaveChanges();
skip = take;
}
catch (Exception ex)
{
Log.Error(ex, "Error saving this data batch! {RecordCount}", take);
IterateSave(items, skip, take);
}
}
}
Как бы вы превратили это в единый универсальный вызов? Я борюсь с тем, что требуется DbSet
и Model
.
Комментарии:
1. Вызовы EF уже являются универсальными. Все вызовы в этих методах уже являются универсальными, за исключением вызовов свойств DbSet<T>
Attributes
иTokenMasters
.2. Что вы пытаетесь сделать с этим кодом? Почему бы не добавить все элементы за один раз? Или используйте SqlBulkCopy для массовой вставки строк с минимальным протоколированием?
3. Получение больших наборов данных из стороннего сервиса REST, плохо определенного, размеры данных меняются, что приводит к сбою вставки. Это, за определенную плату, позволит мне сохранить большую часть данных, когда это произойдет. Выполнение этого за один проход — это только all / none.
4. Вы также можете указать размеры пакетов в SqlBulkCopy. Лучшим вариантом было бы сохранить входящие данные в промежуточной таблице, а затем переместить их в целевую таблицу. Прямо сейчас, для
SaveChanges
сбоя означает, что объекты могут принимать недопустимые данные (почему?) или что контекст EF не синхронизирован с базой данных. Вы должны проверить сущности, прежде чем пытаться их сохранить.5. Все это хороший совет, но не подходит для проблемного пространства, в котором я нахожусь. Поверьте мне, я занимаюсь импортом почти 30 лет. Конечные точки, на которые я натыкаюсь, не имеют определений (поле 1: строка из 50 символов) и могут изменяться без предварительного уведомления. Это серьезный удар по perf для захвата тех записей, которые находятся за пределами предполагаемых границ данных.
Ответ №1:
Это не так просто, как:
private void IterateSave<T>(List<T> items, int min, int max) where T : class
{
int skip = min;
int take = max / 5;
while (skip <= max)
{
try
{
var subItems = items.Skip(skip).Take(take).ToList();
_db.Set<T>().AddRange(subItems);
_db.SaveChanges();
skip = take;
}
catch (Exception ex)
{
Log.Error(ex, "Error saving this data batch! {RecordCount}", take);
IterateSave(items, skip, take);
}
}
}
Комментарии:
1. Да, вы в основном правы. Необходимо изменить определение метода на:
private void IterateSave<T>(List<T> items, int min, int max) where T : class
. Спасибо!