Знакомлюсь с C# и столкнулся со следующей задачей, которую не знаю как решить.
Есть много разных Обьектов, каждый с конечным набором полей, которые заранее известны. Нужно организовать поддержку хранения каждого такого Обьекта в разных базах данных (oracle, mysql, firebird, interbase и postgres). В них он может храниться по разному, вплоть до того, что разные его части будут находиться в разных таблицах, названия полей и таблиц будут отличаться.
(поддержка хранения — в том плане, что в софте должна быть возможность считывать записи из выбранной бд, изменять, удалять их)
Может немного сумбурно задаю вопрос, по ходу дела, если нужно, уточню. Но, может ли кто посоветовать Right Way, Best Practice, подсказать как правильно и красиво это можно реализовать?
Для Entity Framework эта ситуация — штатная, разве что визуальный редактор ее не поддерживает. Создаем одну концептуальную модель, создаем по модели хранения на каждую БД, и для каждой БД создаем свое отображение модели хранения на концептуальную.
Получается, концептуальная модель будет классом для объектов с которыми буду работать, модели хранения для каждой бд — классы, отвечающие за основные операции для каждой отдельной БД?
Можно как-то автоматизировать создание моделей хранение можно?
Что будет отображением модели хранения на концептуальную модель?
спасибо*
Нет. Классы (которые называются сущностями — entities) — это вообще третий слой. Концептуальная модель и модель хранения — это файлы формата xml с расширениями .csdl и .ssdl соответственно.
Автоматизировать создание модели хранения можно, но только для базы данных MS SQL Server — визуальный редактор не умеет работать с другими. Впрочем, формат там не сильно сложный, и инструмент для генерации моделей хранения можно написать и самостоятельно. Или можно создать такую же структуру в MS SQL Server, а потом скопировать результат работы визуального редактора.
Отображение модели хранения на концептуальную — это, кажется, файл с расширением .mdl, формат также xml.
Если это все делать в визуальном редакторе, то все будет сохранено в файле с расширением .edmx, и «растащено» по файлам .csdl, .ssdl и .msl на этапе компиляции проекта, плюс будут автоматически созданы классы сущностей. Но если нужна работа с разными БД — то лучше изначально создавать отдельные файлы, так как .edmx становится слишком большим.
yoshka, а версия 2007 входит в поздние версии? (на неё в плане этой бд и ориентирован) если EF же кажется дружит с драйвером OLE DB, получается что поставщик данных есть.
Входит. Одного OleDb драйвера недостаточно. EF еще необходимо знать, как маппить структуру базы. Для этого EF взаимодействует с поставщиками данных.
Если создать .ssdl-файл с подключение через OleDb, то при создании сущностей будет получена ошибка:
The store provider factory type 'System.Data.OleDb.OleDbFactory' does not implement the IServiceProvider interface. Use a store provider that implements this interface.
Такой провайдер есть под Firebird, но с его помощью можно подключать interbase базы только до определенной версии. Если не ошибаюсь, Interbase 6.0 еще можно подключить, а более поздние версии имеют отличную от фаербердовской структуру файлов БД.
Хм… Могу посоветовать реализовать нужный провайдер поверх OleDb самостоятельно, взяв за основу недостающего функционала код провайдера Firebird. Все-таки EF — достаточно высокоуровневая вещь, чтобы зависеть от таких низкоуровневых форматов БД. Скорее всего, ему надо определить диалект SQL, вроде правил экранирования идентификаторов и способа получения номера вставленного identity.
Но, конечно же, этим стоит заниматься только после проверки остальных методов.
Самое простое — Data Mapper. Создаёте интерфейс для вашей сущности:
interface ICarData
{
void Insert(Car car);
Car GetById(int id);
// и т.д.
}
Затем наследуете от этого интерфейса классы, его реализующие — e.g. MySqlCarData, MongDbCarData.
Отдельная задача здесь — определение, какой класс использовать. Самый простой способ — задавать имя класса через конфигурационный файл и создавать объект нужного класса простой фабрикой (switch(className) {… } ). Более красиво — использовать IoC/DI контейнер.
Обычно используют Object to Relation Mapping (ORM) Frameworks. Мы используем NHibernate (для работы с MSSQL, SQLite и Mysql). Настраивается с помощью адаптеров и если не использовать прямые запросы к БД — то LINQ over NHibernate вполне себе работает с этими БД прозрачно для программиста. Для Interbase и ещо вагона разных БД тоже есть свои адаптеры.
В случае «разные части в разных таблицах» — необходима прослойка data access layer, например для каждого случая хранения. Этот слой будет возвращать набор нужных данных по указанному критерию, изолируя специфику доступа от программиста и делая доступ к БД более прозрачным.