Форум программистов, компьютерный форум, киберфорум
C#: Базы данных, ADO.NET
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.72/18: Рейтинг темы: голосов - 18, средняя оценка - 4.72
11 / 1 / 1
Регистрация: 28.11.2013
Сообщений: 56
1
MS SQL

Грамотно добавлять, удалять, обновлять при foreach

31.07.2018, 11:43. Просмотров 3408. Ответов 44


Добрый день.

Приложение раз в две минуты синхронизирует данные с сервера. Если есть изменения, получает коллекции с итемами по типу изменения updatedItems, createdItems и deleteditems.

Затем прохожусь по каждой коллекции и внутри цикла в зависимости от типа ChangeType
добавляю:
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
List<ItemClass> created_ivents = new List<ItemClass>();
 
                            foreach (newitem in createdItems)
                            {
                                ItemClass item1 = new ItemClass
                                {
                                    Value1 = newitem.Value1,
                                    Value2 = newitem.Value2,
                                    Value3= newitem.Value3
                                };
                                created_ivents.Add(item1);
                            }
 
                            using (DataContext db = new DataContext(connectionString))
                            {
                                // добавляем его в таблицу
                                db.GetTable<ItemClass>().InsertAllOnSubmit(created_ivents);
                                db.SubmitChanges();
                            }
                            created_ivents.Clear();

обновляю:
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
List<ItemClass> updated_ivents = new List<ItemClass>();
                            foreach (newitem in updatedItems)
                            {
                                using (DataContext db = new DataContext(connectionString))
                                {
                                    ItemClass uptditem = db.GetTable<ItemClass>().Where(u => u.UniqueId == newitem.Id).First();
 
                                    uptditem.Value1 = newitem.Value1;
                                    uptditem.Value2 = newitem.Value2;
                                    uptditem.Value3 = newitem .Value3;
 
                                    db.SubmitChanges();
                                }
                            }

и удаляю:
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
foreach (olditem in deleteditems)
                            {
                                using (SqlConnection connection = new SqlConnection(connectionString))
                                {
                                    connection.Open();
                                    string sqlExpression2 = "DELETE FROM Table1 WHERE UniqueId = @UniqueId";
 
                                    SqlCommand com = new SqlCommand(sqlExpression2, connection)
                                    {
                                        CommandType = System.Data.CommandType.Text
                                    };
 
                                    com.Parameters.AddWithValue("@UniqueId", olditem.ItemId);
                                    com.CommandText = sqlExpression2;
                                    int result = com.ExecuteNonQuery();
                                    //Console.WriteLine("Удалено {0}", result);
                                }
                            }


Грубо говоря, при создании foreach загоняет все в лист и 1 раз InsertAllOnSubmit(). При удалении каждый раз внутри foreach sql-запрос на удаление по id (т.е. если 10 или 20 удаленных записей, то будет 10 или 20 запросов). При обновлении каждый раз внутри foreach получаю элемент, обновляю все значения и SubmitChanges(), при этом на сколько я понял linq кэширует, сверяет запись и затем обновляет, т.е. вон сколько всего.

Вопрос: как сделать грамотно? Или и так сойдет?)
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
31.07.2018, 11:43
Ответы с готовыми решениями:

Как добавлять и удалять записи из БД и будет ли это приложение (будильник) работать на других ПК
Доброго времени суток! Помогите новичку разобраться. Стоит задача: написать напоминалку...

Как в datagrid добавлять и удалять колонки
Как можно сделать динамическое добавление и удаление колонок в datagrid? В devexpress есть...

Как удалять и добавлять вертексы в шейдер?
Всё копаюсь с морфингом. Есть необходмость в определённые момент добавлять некоторые НОВЫЕ грани в...

Как добавлять и удалять элементы из очереди?
Не нашел методы Push и Pop для очереди.

44
5 / 5 / 1
Регистрация: 29.06.2018
Сообщений: 24
31.07.2018, 14:34 2
Цитата Сообщение от spektr_011 Посмотреть сообщение
Если есть изменения
Цитата Сообщение от spektr_011 Посмотреть сообщение
как сделать грамотно? Или и так сойдет?)
Грамотно , это считывать ресурсы непосредственно при работе с ними .
То есть загрузка данных не должна происходить пару раз , допустим при загрузке данных и соответственно при нажатии на кнопочку Refresh/Update . Начинается работа с данными , перед этим загружайте их . Тут и отпадет надобность автономной синхронизации , и отказоустойчивость повысится .

Но если прям надо автономно , то лучше будет ловить сами изменения со стороны сервера, и только тогда обновляться на стороне юзера . Реализации давно лежат на просторах интернета .
0
1514 / 1079 / 151
Регистрация: 23.07.2010
Сообщений: 5,946
31.07.2018, 15:11 3
задай себе простой вопрос - что начнется, когда приложение запустят так 100500 раз практически одновременно?
0
11 / 1 / 1
Регистрация: 28.11.2013
Сообщений: 56
31.07.2018, 15:26  [ТС] 4
NeSpe******t, немного не допетриваю в силу неграмотности.

Цитата Сообщение от NeSpe******t Посмотреть сообщение
загрузка данных не должна происходить пару раз
Получаю только вновь созданные, удаленные или измененные. Дальше прогоняю через foreach и идет разбивка. На три цикла разбил для примера. На деле что-то типа:
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
foreach (newitem in newItems)
                            {
if (newitem.ChangeType == ChangeType.Create)
{
добавляю
}
else
if (newitem.ChangeType == ChangeType.Update)
{
обновляю
}
if (newitem.ChangeType == ChangeType.Delete)
{
удаляю
}}


Автономная синохроиназция потому что я не могу читать бд из первоисточника, приходится синхронизировать и сливать к себе, например, раз в 2 минуты на бесконечном цикле. Соответственно никакой кнопки нет. Позже вероятно перейдем на свою бд.
Поэтому сейчас эта костылина работает, но вот допустим 20 новых изменений (30, 40) и foreach будет раскидывать по типу, и, если удаление или обновление, 20 (30,40) запросов.

Цитата Сообщение от NeSpe******t Посмотреть сообщение
Реализации давно лежат на просторах интернета .
Хотя бы как загуглить?

Добавлено через 8 минут
pincet,

как я уже написал, эта приблуда в единственно-запущенном экземпляре у меня сливает в фоне итемы с источника ко мне в бд. Вопрос в том, если новых итемов 100500 (что почти никогда не произойдет), то будет 10500 sql комманд на удаление или обновление по id. Круче, чем "синхронизация" и получать только новые итемы, не нашел.
0
1514 / 1079 / 151
Регистрация: 23.07.2010
Сообщений: 5,946
31.07.2018, 15:32 5
на самом деле держать данные актуальными в распределенных системах - очень и очень непростая задача

Добавлено через 2 минуты
Цитата Сообщение от spektr_011 Посмотреть сообщение
эта приблуда в единственно-запущенном экземпляре у меня сливает в фоне
вот твое самое главное заблуждение. где гарантия, что во время твоей "синхронизации" никто не высрет новых записей и не удалит существующих?

Добавлено через 1 минуту
другое дело, что источник данных тоже контролируется тобой (некоей API)

Добавлено через 1 минуту
Цитата Сообщение от spektr_011 Посмотреть сообщение
то будет 10500 sql комманд на удаление или обновление по id.
ответ неверный. все нужно на API (DAL) возлагать, а уж там писать грамотные запросы без 100500 скриптов
0
Эксперт .NET
8655 / 6117 / 1019
Регистрация: 21.01.2016
Сообщений: 23,091
31.07.2018, 17:28 6
spektr_011, это две базы синхронизируются? Синхронизация в одну сторону? Схемы совпадают? Может применить репликацию, если возможно?

Тут точно нужен EF? Голым SQL-ем было бы поэффективнее. Те же удаления можно в одну ходку выполнить, через DELETE FROM ... WHERE Id IN (Id1, Id2, Id3...).
0
11 / 1 / 1
Регистрация: 28.11.2013
Сообщений: 56
31.07.2018, 17:40  [ТС] 7
Цитата Сообщение от pincet Посмотреть сообщение
вот твое самое главное заблуждение. где гарантия, что во время твоей "синхронизации" никто не высрет новых записей и не удалит существующих?
Добавлено через 1 минуту
другое дело, что источник данных тоже контролируется тобой (некоей API)
источник заполняется пользователями. по-моему ничего страшного не произойдет. пишется некая кэш строка и с ней сверяется. изменения подтянутся либо в этом, либо в следующем выполнии цикла.

Цитата Сообщение от pincet Посмотреть сообщение
все нужно на API (DAL) возлагать, а уж там писать грамотные запросы
это я в общем то и спрашивал с начала. как?)

Цитата Сообщение от Usaga Посмотреть сообщение
это две базы синхронизируются?
нет. тяну данные из exchange с помощью ews managed api к себе в таблицу. сейчас это в одну сторону.

Цитата Сообщение от Usaga Посмотреть сообщение
можно в одну ходку выполнить
вот что-то типа этого для удаления и обновления. чтобы скопом. или как организовать DAL в консольной api.
0
Эксперт .NET
8655 / 6117 / 1019
Регистрация: 21.01.2016
Сообщений: 23,091
31.07.2018, 17:43 8
Цитата Сообщение от spektr_011 Посмотреть сообщение
вот что-то типа этого для удаления и обновления. чтобы скопом. или как организовать DAL в консольной api.
Удалить можно одним скопом, я показал как. А обновление и добавление за раз не получится, но можно сформировать длинные запросы (на чистом SQL), с группами инструкций вставки и обновления. Т.е. обращение будет одно, просто запросище будет длинный.

Ну и размеры таких запросов ну надо делать сильно большими, это тоже негативно скажется на производительности.
0
11 / 1 / 1
Регистрация: 28.11.2013
Сообщений: 56
31.07.2018, 17:45  [ТС] 9
Цитата Сообщение от Usaga Посмотреть сообщение
добавление за раз не получится
добавление вроде вышло.
C#
1
2
db.GetTable<ItemClass>().InsertAllOnSubmit(created_ivents);
db.SubmitChanges();
где created_ivents - список нужных итемов.
0
Эксперт .NET
8655 / 6117 / 1019
Регистрация: 21.01.2016
Сообщений: 23,091
31.07.2018, 17:55 10
Да, точно, есть же InsertAllOnSubmit.

Обновление оформите иначе. Или создайте один контекст вне цикла, а внутри только выгружайте сущности обновляйте им свойства, а после цикла уже вызывайте сохранение. Но тут кеш контекста уже скажется на производительности. Я хз как с ним работать в LinqToSQL (технология уже заброшенная, я ей не пользуюсь). Или вручную запрос состряпайте, там кеша никакого не будет.
0
11 / 1 / 1
Регистрация: 28.11.2013
Сообщений: 56
31.07.2018, 18:10  [ТС] 11
Цитата Сообщение от Usaga Посмотреть сообщение
технология уже заброшенная
за этим и пишу - как правильно сделать. наколхозить с кэшем и сам горазд). Хоть большой нагрузки и не будет, но надо же нормально.
0
70 / 66 / 47
Регистрация: 02.12.2015
Сообщений: 809
Записей в блоге: 1
31.07.2018, 19:32 12
Цитата Сообщение от Usaga Посмотреть сообщение
Тут точно нужен EF? Голым SQL-ем было бы поэффективнее. Те же удаления можно в одну ходку выполнить, через DELETE FROM ... WHERE Id IN (Id1, Id2, Id3...).
На чистом sql будет быстрее? И вообще удаления обновления лучше через sql делать чем через EF?
0
1514 / 1079 / 151
Регистрация: 23.07.2010
Сообщений: 5,946
31.07.2018, 20:53 13
Я так понял нужно на коленках репликацию устроить руками. Абстрагируясь от сервера данных и его возможностей, в лоб, так сказать, надёжнее всего получать все данные из исходника (помечая каждую запись неким timestamp) вливать в базу и при успешном завершении удалять все старые (со старым timestamp, коий текущий хранится для каждой таблицы в служебной). Видел такие решения, работают. Синхронизация запускается по расписанию, когда есть минимальные нагрузки, если это возможно. Если нет - тогда уж решение сильно усложняется, ибо распределённая работа

Добавлено через 8 минут
Цитата Сообщение от Usaga Посмотреть сообщение
DELETE FROM ... WHERE Id IN (Id1, Id2, Id3...).
Всяко-разно лучше не перечислять , а явный набор данных указать (subquery)
0
Эксперт .NET
8655 / 6117 / 1019
Регистрация: 21.01.2016
Сообщений: 23,091
01.08.2018, 06:35 14
Цитата Сообщение от spektr_011 Посмотреть сообщение
а этим и пишу - как правильно сделать. наколхозить с кэшем и сам горазд). Хоть большой нагрузки и не будет, но надо же нормально.
Если данных немного и производительность не страдает, то можно и так оставить. Только я бы выкинул LinqToSQL и использовал другую ORM. И удаление запросом бы тоже убрал и возложил на плечи ORM, иначе криво выходит: в одном месте через ORM, в другом - вручную.

Если будут проблемы с производительностью (долгий процесс импорта), то уже рассмотрел бы ручные запросы на обновление и удаление. Вносил бы данные пачками (записей по пятьдесят-сто), одной ходкой.

Цитата Сообщение от aleksskay4 Посмотреть сообщение
На чистом sql будет быстрее? И вообще удаления обновления лучше через sql делать чем через EF?
Речь в этой теме именно о batch-запросах. Т.е. внесении изменений в базу целыми пачками. Если таких пачек немного, то и EF отлично справится (ТС использует LinqToSQL, а не EF!). Если нужно будет оптимизировать, то лучше голый SQL-запрос.

Цитата Сообщение от pincet Посмотреть сообщение
Всяко-разно лучше не перечислять , а явный набор данных указать (subquery)
Какой набор данных, когда у нас на руках пачка ID?
1
1514 / 1079 / 151
Регистрация: 23.07.2010
Сообщений: 5,946
01.08.2018, 11:27 15
Цитата Сообщение от Usaga Посмотреть сообщение
Какой набор данных, когда у нас на руках пачка ID?
пачка ID берется-же откуда-то?
0
Эксперт .NET
8655 / 6117 / 1019
Регистрация: 21.01.2016
Сообщений: 23,091
01.08.2018, 11:35 16
pincet, из другого сервиса (не из этой же базы). Так что подзапрос не к месту (нечего подзапрашивать).
0
1514 / 1079 / 151
Регистрация: 23.07.2010
Сообщений: 5,946
01.08.2018, 13:35 17
Usaga, такой IN сервер развернет в OR и будут печали
0
Эксперт .NET
8655 / 6117 / 1019
Регистрация: 21.01.2016
Сообщений: 23,091
01.08.2018, 13:37 18
pincet, значит последовательность команд DELETE в один запрос утрамбовать.
0
1514 / 1079 / 151
Регистрация: 23.07.2010
Сообщений: 5,946
01.08.2018, 13:41 19
коль скоро в сабже прозвучало про MS SQL, может select @@version стоит озвучить?
0
11 / 1 / 1
Регистрация: 28.11.2013
Сообщений: 56
01.08.2018, 14:31  [ТС] 20
Цитата Сообщение от pincet Посмотреть сообщение
может select @@version стоит озвучить?
это можно: Microsoft SQL Server 2014 - 12.0.2000.8 (X64)
Feb 20 2014 20:04:26
Copyright (c) Microsoft Corporation
Express Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
01.08.2018, 14:31

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь.

Возможность добавлять и удалять поля в модуле
Уважаемые специалисты, помогите разобраться: Нужно реализовать в модуле возможность добавления и...

Объясните как удалять, добавлять и сортировать строки
подскажите, пожалуйста,как удалять, добавлять и сортировать строки? мне казалось,что через...

Как правильнее добавлять и удалять заголовки сообщений?
Как правильнее добавлять и удалять заголовки сообщений: делать экземпляр HttpRequestMessage или...

Как динамически добавлять/удалять страницы ViewPager
Добрый день Всем! как можно добавлять и удалять страницы во ViewPager? пытаюсь делать так: ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.