Чтение и запись данных на MS SQL Server с помощью OLE DB и ADO.NET

Временами у программистов возникает жгучее желание прочитать что-то из базы данных. Программисты становятся нервными и раздражительными, теряют сон и лихорадочно тыкают пальцами в клавиатуру. Ради всеобщего блага и мира во всем мире рассмотрим несложную работу с базой данных из C# с помощью ADO.NET и OLE DB. Хотя данный механизм поддерживает разные базы данных вроде Oracle, здесь и сейчас будем использовать MS SQL Server.

Две основных задачи при работе с базой данных

1. Считать данные по select в DataTable, для дальнейшей обработки или вывода на экран

2. Выполнение sql-команды, что-то делающей на сервере (insert, update, delete, вызов функции или хранимой процедуры

3. Последовательное чтение из select-выборки строки за строкой. В основном используется в веб-приложениях, в настольных проще скачать сразу всю выборку в оперативную память, экономия от чтения только нужных строк незначительна.

4. Редкий случай. Автоматическое обновление таблицы в базе на основании изменений в DataTable (как правило редактируемой через визуальный интрфейс). В реальной жизни данные обычно читаются через сложный запрос с кучей join или представление, так что автоматическая синхронизация не подходит.

Основные классы, используемые для этих целей: OleDbConnection - соединение с базой, создаем со строкой, содержащей параметры соеднинения, открываем, закрываем, OleDbCommand - создаем с экземпляром соединения и sql-командой, если нужно просто выполнить update или получить единичное значение, то хватит этого класса, OleDbDataAdapter - создается с OleDbCommand, специализируется на разовом чтении наборов строк в DataTable, может автоматически создавать колонки DataTable на основании выборки, переносить изменения из DataTable в таблицу в базе, OleDbDataReader - последовательное чтение строк в DataTable по одной за раз (он работает внутри OleDbDataAdapter), DataTable/ DataSet - основной контейнер для данных. В перечислении OleDbType хранятся типы данных базы данных.

1. Считать данные по select в DataTable, для дальнейшей обработки или вывода на экран
Читать далее

Оператор insert into ... select в transact sql

Обычный оператор вставки значений в таблицу INSERT:

 
INSERT INTO SOME_TABLE (TEXT_FIELD, INT_FIELD) VALUES 'Компьютер имеет то преимущество перед мозгом, что им пользуются',24)

Для вставки в таблицу выборки строк из другой таблицы используется следующее выражение:

 
INSERT INTO SOME_TABLE2 (TEXT_FIELD2, INT_FIELD2) SELECT TEXT_FIELD, INT_FIELD FROM SOME_TABLE

Если таблица простая, то копирование данных можно совместить с ее созданием

 
--SELECT какие_столбцы_переносить INTO имя_создаем_таблицу_куда-переносим FROM таблица_откуда_переносим

SELECT TEXT_FIELD, INT_FIELD INTO SOME_TABLE2 FROM SOME_TABLE

Для сложных таблиц это не сработает, например свойство IDETITY пропадет - их надо копировать иначе.

Как пренести таблицу MS SQL Server на другой сервер/базу с сохранением IDENTITY

Иногда на разных серверах-базах надо иметь точные копии одной и той же таблицы, содержащей столбец IDENTITY, значения которого должны быть уникальны и генерятся автоматически. Простые операторы выборки и вставки не помогают, особенно если некоторые строки удалялись и коды идут непоследовательно (1,2,4,5,9). Для временного отключения генерации identity при вставке данных в таблицу используется свойство IDENTITY_INSERT:

SET IDENTITY_INSERT SOME_TABLE ON 
INSERT INTO SOME_TABLE (IDENTITY_FIELD, SOME_FIELD) VALUES(101, 'Деньги - это зло. Но добро побеждает зло. Поэтому, если ты добрый - денег у тебя не будет.')
SET IDENTITY_INSERT SOME_TABLE OFF 

тема на форуме sql.ru

Всплывающая подсказка не показывается после клика на кнопке - C#, WinForms

Имеем умную, красивую и обаятельную кнопку со всплывающей подсказкой (ToolTip) и не менее очаровательную проблему - после клика по кнопке всплывающая подсказка перестает всплывать. И что делать? Судя по всему это глюк то ли .Net то ли самих Windows, решается он просто, но несколько неочевидно - на само событие клика вешаем такой код (найден на vbforums.com):

someToolTip.Active = false;
someTip.Active = true;

Звучит бредово, но работает - это главное. Проверялось в VS2008. Кстати, если программист брезгливо морщится при виде визуального редактора и прям-таки горит желанием добавить всплывающую подсказку вручную, ему поможет следующее заклинание:
Читать далее

Особенности связки ComboBox с DataTable и ошибка с System.Data.DataRowView

Программисты - существа капризные и непредсказуемые. Иногда у них возникает желание заполнить ComboBox данными из DataTable вручную, не используя визуальную среду. Делается это следующим образом:

someComboBox.DataSource = someDataTable;
someComboBox.DisplayMember = "FIELD_TO_DISPLAY";
someComboBox.ValueMember = "FIELD_TO_HIDE";

Не заполнив DisplayMember и ValueMember можно получить совершенно невнятную ошибку - ComboBox будет заполнен строками "System.Data.DataRowView" (подробнее на StackOverFlow).

Так же ее можно получить, попытавшись прочитать выбранное значение до установки свойства DisplayMember - на самом деле это не так уж и сложно, установка значения DataSource вызывает событие SelectedIndexChanged - на которое нередко вешается обработка.

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

Если же мы хотим получить именно текст выбранного в ComboBox пункта, то надо использовать не кажущееся самоочевидным свойство SelectedText, а просто Text.

Глядя на свойства SelectedItem, SelectedIndex и SelectedValue начинающий программист может подумать, что SelectedText так же содержит текст выбранного пункта, но на самом деле оно содержит выделенную мышкой часть текста выбранного пункта - и в большинстве случаев пустое, а если свойство DropDownStyle имеет значение DropDownList - то SelectedText будет пустым всегда.

Как вставить строку на заданную позицию DataTable

Иногда надо вставить дополнительную строку на заданную позицию в DataTable. Алгоритм прост, создаем пустой DataRow, соответствующий структуре данной таблицы, с помощью метода NewRow(), заполняем его данными и добавляем в коллекцию строк методом InsertAt().

DataRow rowToAdd = someDataTable.NewRow();
rowToAdd["ID"] = -1;
rowToAdd["TEXT_FIELD"] = "ID = -1, WOW!!!!";
someDataTable.Rows.InsertAt(rowToAdd, 0);

Глюк с копированием данных в буфер из DataGridView

Есть DataGridView с некими мега-важными данными, которые мы хотим скопировать в Excel через гениальную особенность ОС Windows "буфер обмена". Преисполненные самых радужных надежд жмем Ctrl+C, Ctrl+V и получаем тотальную абракадабру в левой кодировке. "Если видишь в стенке люк, не пугайся - это глюк." В данном случае глюк .Net и Visual Studio (как минимум 2008). Можно слать мольбы и проклятия далеким редмондским богам, можно просто повесить следующий код на событие KeyDown нашего DataGridView.

// правильное копирование в буфер
private void copySelectedRowsToClipboard(DataGridView dgv)
{
    dgv.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
    Clipboard.Clear();
    if (dgv.GetClipboardContent() != null)
    {
        Clipboard.SetDataObject(dgv.GetClipboardContent());
        Clipboard.GetData(DataFormats.Text);
        IDataObject dt = Clipboard.GetDataObject();
        if (dt.GetDataPresent(typeof(string)))
        {
            string tb = (string)(dt.GetData(typeof(string)));
            Encoding encoding = Encoding.GetEncoding(1251);
            byte[] dataStr = encoding.GetBytes(tb);
            Clipboard.SetDataObject(encoding.GetString(dataStr));
        }
    }
    dgv.ClipboardCopyMode = DataGridViewClipboardCopyMode.Disable;
}

// привязка к событию копирования
private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.C)
    if (((DataGridView)sender).SelectedCells.Count > 0)
    {
        copySelectedRowsToClipboard((DataGridView)sender);
    }
}

Transact SQL и MS SQL Server - получаем список ролей для текущего пользователя и всех пользователей

Механизм ролей в MS SQL Server не так прост, как кажется, если имя пользователя добывается легко и непринужденно:

SELECT SYSTEM_USER

то список ролей можно получить с помощью утюга, паяльника, дыбы, испанского сапога и следующего запроса

--- РОЛИ ДЛЯ ТЕКУЩЕГО ПОЛЬЗОВАТЕЛЯ
WITH CTE_Roles (role_principal_id)
AS
(
SELECT role_principal_id 
FROM sys.database_role_members
WHERE member_principal_id = USER_ID()
UNION ALL
SELECT drm.role_principal_id
FROM sys.database_role_members drm
  INNER JOIN CTE_Roles CR
    ON drm.member_principal_id = CR.role_principal_id
)
SELECT USER_NAME(role_principal_id) RoleName
FROM CTE_Roles
UNION ALL
SELECT 'public'
ORDER BY RoleName;

Типичный программист любопытен, хочет все знать и не ищет простых путей - подробную информацию о всех пользователях базы данных он выведет следующим запросом
Читать далее

Определяем название метода и класса, выполняющихся в данный момент

Определить название метода можно с помощью метода MethodBase.GetCurrentMethod или аналогичного метода класса MethodInfo

string currMethodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
//то же самое
currMethodName =  System.Reflection.MethodInfo.GetCurrentMethod().Name; 

Оба метода возвращают одно и то же значение. Какой использовать? GetCurrentMethod() - это общий (shared) метод классов MethodBase и MethodInfo. Но класс MethodInfo является производным от класса MethodBase и просто наследует GetCurrentMethod() без изменений. Таким образом лучше использовать метод исходного класса MethodBase.GetCurrentMethod() - если не вдаваться в технические сложности, по нему проще найти документацию, то есть код будет более понятнее (более подробно на bytes.com).

Название класса, к которому принадлежит текущий обьект

this.GetType().ToString()

Файлы в C# - проверяем наличие файла, определяем размер, дату последнего изменения, перемещаем удаляем

Проверить, существует ли файл, можно с помощью функции Exists класса File

if(!(File.Exists(filePath)) ) {/*все пропало, файла нет, надо срочно что-то делать*/ } 

Получить список путей к файлам в каталоге - Directory.GetFiles

string[] filePaths = Directory.GetFiles(someDirectoryPath);

Проверить, существует ли каталог и создать новый - Directory.Exists и Directory.CreateDirectory
Читать далее