EF AddRange метод не работает с большими данными - PullRequest
0 голосов
/ 08 мая 2019

Доброе утро.

Сегодня у меня проблема с EF 6 и AddRange методом.Есть приложение WPF, которое работает с ~ 100000 записей.Я написал функцию импорта, которая импортирует данные из CSV-файлов, и возникает проблема.

Это выглядит так:

 private void FileImport()
    {
        //Open dialog to choose file
        OpenFileDialog ofd = new OpenFileDialog();

        string fileName = string.Empty;

        if (ofd.ShowDialog() == true)
        {
            fileName = ofd.FileName;
        }

        if (!string.IsNullOrEmpty(fileName))
        {
            //getting all lines
            var lines = File.ReadAllLines(fileName).ToList();

            //File requirements says that there cannot be empty values in first element
            if (lines.Any(line => line.Split(';')[0].Equals("null")))
            {
                MessageBox.Show("BLA BLA BLA");
            }
            else
            {

                List<List<string>> splitLines = new List<List<string>>();

                //split lines into smaller list. For every sublist in list we will do things separatly in separate threads to get it faster.
                for (int i = 0; i < lines.Count; i += 1000)
                {
                    splitLines.Add(lines.GetRange(i, Math.Min(1000, lines.Count - i)));
                }

                var taskList = new List<Task>();

                List<ut_katabcdx_file_filters> filterList = new List<ut_katabcdx_file_filters>();

                foreach (var list in splitLines)
                {
                    //define a Task
                    var t = new Task(() =>
                    {
                        foreach (var line in list)
                        {
                            var filters = line.Split(';');

                            //split line into elements array. It must have 6 elemets
                            if (filters.Count() == 6)
                            {

                                //Temporary declaration for parsing. If element that pretends to be decimals are empty we set its value to -100000.
                                decimal temp;
                                int tempi;
                                decimal? proga = filters[1].Equals("") ? -100000 : (decimal.TryParse(filters[1], out temp) ? (decimal?)temp : null);
                                decimal? progb = filters[2].Equals("") ? -100000 : (decimal.TryParse(filters[2], out temp) ? (decimal?)temp : null);
                                int? plan_sprz_rok = filters[3].Equals("") ? -100000 : (int.TryParse(filters[3], out tempi) ? (int?)tempi : null);

                                ut_katabcdx_file_filters filter = new ut_katabcdx_file_filters()
                                {
                                    indeks = filters[0],
                                    //produkty_iz = ProduktyIzChecked ? (filters[1].Equals("null") ? null : filters[1]) : string.Empty,
                                    proga = ProgaChecked ? proga : -100000,
                                    progb = ProgbChecked ? progb : -100000,
                                    plan_sprz_rok = PlanSprzRokChecked ? plan_sprz_rok : -100000,
                                    kat_tech = KatTechChecked ? (filters[4].Equals("null") ? null : filters[4]) : string.Empty,
                                    kat_handl = KatHandlChecked ? (filters[5].Equals("null") ? null : filters[5]) : string.Empty,
                                };

                                filterList.Add(filter);
                            }
                        }
                    });

                    taskList.Add(t);
                    t.Start();
                }

                //wait for all tasks to end
                Task.WaitAll(taskList.ToArray());

                using (var ctx = new ABCDXContext())
                {
                    ctx.ut_katabcdx_file_filters.AddRange(filterList);
                    ctx.SaveChanges();
                    string param_xml = GetParamXml();
                    Products = new ObservableCollection<ut_katabcdx_wytwor>(ctx.WytworFileUpdate(param_xml));
                }
            }

        }
    }

Когда я отлаживаю код, он останавливается на ctx.ut_katabcdx_file_filters.AddRange(filterList);и не идет дальше.Я проверил filterList.Count и там около 60000 строк.Я также проверил таблицу базы данных, но она пуста.

Это потому, что большой объем данных или я что-то делаю неправильно?Буду очень признателен за любые советы.

1 Ответ

0 голосов
/ 08 мая 2019

Я согласен с комментарием DavidG о попытке вставить 60k записей, используя AddRange.Это будет медленно.Вам придется либо просто дождаться его окончания, либо найти альтернативу.

Я обнаружил, что ваш Context будет счастливее, когда вы периодически звоните SaveChanges.Кажется, что накопление большого количества элементов в трекере изменений - огромный удар по производительности.

Так что вы можете сделать что-то вроде этого:

using (var ctx = new ABCDXContext())
{
    var count = 0;
    foreach (var filter in filterList)
    {
        ctx.ut_katabcdx_file_filters.Add(filter);
        count++;
        if (count > 100)
        {
            ctx.SaveChanges();
            count = 0;
        }
    }
    if (count > 0)
        ctx.SaveChanges();
    string param_xml = GetParamXml();
    Products = new ObservableCollection<ut_katabcdx_wytwor>(ctx.WytworFileUpdate(param_xml));
}

... просто чтобы разбитьсохранить в блоках.Вы можете настроить count на значение, которое уравновешивает производительность для вашего сценария.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...