На C# я пишу редко, и в основном все наши приложения и сервисы подключаются к источнику данных, используя MSSQL сервер или службы баз данных. И вот настало время написать приложение, используя не сервер, а локальную БД. Немного погуглив, я внезапно выбрал SQLite.
У всех наших заказчиков были требования к коду:
Исходя из вышеперечисленного, для баз данных конечно же были использованы классы LINQ to SQL, связанные с реляционными объектами.
Естественно, в моем десктопном приложении я сразу же скачал и установил SQLite провайдер, создал базу данных, все таблички, связи, создал класс LINQ to SQL, перетянул в него все объекты с обозревателя, и…

Конечно же в гугл, с которого плавно перебегаем в stackoverflow! Там у нас over9000 вариантов:
Нет, нет, и еще раз нет. С данными должен работать класс, который отвечает за подключение к БД, выборку, вставку, обновление и удаление записей (DataContext), а разработчик должен использовать объекты, именованные так же, как и реляционные объекты и их свойства!
Больше ничего не осталось, как искать «левые» генераторы кода для таблицы. Немного погуглив и взвесив все «за» и «против», я остановился на dblinq2007.
Как оказалось позже, он может генерировать не просто файл с исходным кодом, а студийный LINQ to SQL файл со схемой нашей БД и связями! Это как раз то, что и нужно было, и я приступил к разработке. Первый exception: dblinq2007 написан и генерирует схему для Framework 2.0, а мы используем 4.0. Качаем исходники, открываем в студии, в свойствах проектов выбираем 4ю версию фреймворка и пересобираем dblinq2007!
Для генерации необходимо использовать исполняемый файл dblinq2007, который лежит в директории скомпилированных бинарников и называется DbMetal.exe. Немного покурим его доки, и, просмотрев справку, мы видим, что достаточно указать провайдера, строку подключения и имя файла, и DbMetal сгенерирует нам DBML файл для SQLite:

Генерируем DBML-модель:

После генерации DBML нам необходимо сгенерировать CS файл (должен называться так же, как и DBML файл), в котором и будет описана структура нашей БД со всеми связями. Основной сгенерируемый класс Main унаследован от класса DataContext, в котором и реализована работа с SQLite.

Теперь, когда все файлы сгенерированы, копируем их в директорию нашего проекта и добавляем в проект DBML файл. Чтобы увидеть, что студия теперь работает с SQLite, достаточно в Обозревателе серверов выделить все таблички, и перетянуть их в DBML конструктор:

Победа!

В принципе, все. После проделанных манипуляций мы сможем писать LINQ запросы к нашей БД и нам будут возвращаться объекты со всеми связями.
Предисловие
У всех наших заказчиков были требования к коду:
- установленное именование переменных;
- группировка кода (конструкторы, переменные, методы, события...);
- табы и форматирование (каралось смертной казнью);
- за самописные SQL запросы разработчик удалялся из команды.
Исходя из вышеперечисленного, для баз данных конечно же были использованы классы LINQ to SQL, связанные с реляционными объектами.
Естественно, в моем десктопном приложении я сразу же скачал и установил SQLite провайдер, создал базу данных, все таблички, связи, создал класс LINQ to SQL, перетянул в него все объекты с обозревателя, и…

приехали

Что делать? Куда бежать?
Конечно же в гугл, с которого плавно перебегаем в stackoverflow! Там у нас over9000 вариантов:
- да давайте все писать с начала (SQLiteConnection, SQLiteCommand, SQLiteDataReader, SQLiteDataRecord и т.д.):
- давайте писать запросы вручную;
- давайте при изменении или добавлении одного поля в таблицу перелопатим весь проект;
- связи между таблицами для слабаков, будем использовать DataTable и работать с ним по индексам столбцов...
Нет, нет, и еще раз нет. С данными должен работать класс, который отвечает за подключение к БД, выборку, вставку, обновление и удаление записей (DataContext), а разработчик должен использовать объекты, именованные так же, как и реляционные объекты и их свойства!
Решение
Больше ничего не осталось, как искать «левые» генераторы кода для таблицы. Немного погуглив и взвесив все «за» и «против», я остановился на dblinq2007.
Как оказалось позже, он может генерировать не просто файл с исходным кодом, а студийный LINQ to SQL файл со схемой нашей БД и связями! Это как раз то, что и нужно было, и я приступил к разработке. Первый exception: dblinq2007 написан и генерирует схему для Framework 2.0, а мы используем 4.0. Качаем исходники, открываем в студии, в свойствах проектов выбираем 4ю версию фреймворка и пересобираем dblinq2007!
Генерация кода
Для генерации необходимо использовать исполняемый файл dblinq2007, который лежит в директории скомпилированных бинарников и называется DbMetal.exe. Немного покурим его доки, и, просмотрев справку, мы видим, что достаточно указать провайдера, строку подключения и имя файла, и DbMetal сгенерирует нам DBML файл для SQLite:

Генерируем DBML-модель:

После генерации DBML нам необходимо сгенерировать CS файл (должен называться так же, как и DBML файл), в котором и будет описана структура нашей БД со всеми связями. Основной сгенерируемый класс Main унаследован от класса DataContext, в котором и реализована работа с SQLite.

Теперь, когда все файлы сгенерированы, копируем их в директорию нашего проекта и добавляем в проект DBML файл. Чтобы увидеть, что студия теперь работает с SQLite, достаточно в Обозревателе серверов выделить все таблички, и перетянуть их в DBML конструктор:

Победа!

В принципе, все. После проделанных манипуляций мы сможем писать LINQ запросы к нашей БД и нам будут возвращаться объекты со всеми связями.
public class Test
{
private void Example()
{
//берем из конфига строку подключения и подключаемся к БД
SQLiteConnection Connection = new SQLiteConnection(Properties.Settings.Default.connectionString);
Connection.Open();
//тот самый DatabaseContext, через который мы работаем с БД
Main dbContext = new Main(Connection, new SqliteVendor());
//получаем данные
List<Order> OrderList = (from o in dbContext.Order
select o).ToList();
//или так
List<Order> OrderList = dbContext.Order.Take(10).ToList();
//получаем статус заказа из связанной таблицы
string OrderStatus = OrderList[0].OrderStatus.Name;
//получаем все позиции заказа
List<OrderUnit> OrderUnits = OrderList[0].OrderUnit.ToList();
//получаем изображения позиции
List<MenuImages> UnitImages = OrderList[0].OrderUnit[0].Menu.MenuImages.ToList();
//вставляем данные
Order ord = new Order()
{
OrderNumber = 1,
ToTime = DateTime.Now
};
dbContext.Order.InsertOnSubmit(ord);
dbContext.SubmitChanges();
//Удаляем данные
dbContext.Order.DeleteOnSubmit(OrderList[0]);
dbContext.SubmitChanges();
//закрываем подключение
Connection.Close();
}
}