Архитектура доступа к бд
От: BlackEric http://black-eric.lj.ru
Дата: 17.04.19 13:42
Оценка:
Есть старое веб формс приложение, работающее с ms sql. В нем запросы для доступа к бд хранятся в классах в виде строк и в них же при необходимости формируются.
Теперь нужно добавить работу с postgre sql.
Я понимаю, что это классический случай применения Entity Framework, но в данном случае это будет означать с нуля переписать всю работу с бд. А работу с ms sql трогать нельзя и нужно продолжать развивать.
Пока не придумали ничего лучше чем писать:
if (mssql)
{
    return mssqlQuery;
}
else
{
    return postgresQuery;
}


Какие еще есть варианты?
https://github.com/BlackEric001
Re: Архитектура доступа к бд
От: · Великобритания  
Дата: 17.04.19 13:50
Оценка: +2
Здравствуйте, BlackEric, Вы писали:

BE>Какие еще есть варианты?

DAO же, классика.

interface UserDao{
  User GetSomeUser();
}

class MssqlUserDao : UserDao {
  User GetSomeUser()
  {
     return new User ...(mssql.query("SELECT TOP 1..."));
  }
}
class PsqlUserDao : UserDao {
  User GetSomeUser()
  {
     return new User ...(psql.query("SELECT... LIMIT 1"));
  }
}


Притом рефакторинг вполне очевидный — вначале выделить слой Dao с единственной имплементацией Mssql, потом потихоньку начать создавать Psql и заменять реализацию.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[2]: Архитектура доступа к бд
От: BlackEric http://black-eric.lj.ru
Дата: 17.04.19 14:06
Оценка:
Здравствуйте, ·, Вы писали:

·>DAO же, классика.


·>Притом рефакторинг вполне очевидный — вначале выделить слой Dao с единственной имплементацией Mssql, потом потихоньку начать создавать Psql и заменять реализацию.


Да, DAO выделяться будет.
Я вот думаю может работу с PostgreSql писать на linq2db, а потом все заменить на нее, потому что если потом захотят 3 базу поддерживать то это будет закопаться.
https://github.com/BlackEric001
Re[3]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 14:50
Оценка:
Здравствуйте, BlackEric, Вы писали:

BE>Здравствуйте, ·, Вы писали:


BE>·>DAO же, классика.


BE>·>Притом рефакторинг вполне очевидный — вначале выделить слой Dao с единственной имплементацией Mssql, потом потихоньку начать создавать Psql и заменять реализацию.


BE>Да, DAO выделяться будет.

BE>Я вот думаю может работу с PostgreSql писать на linq2db, а потом все заменить на нее, потому что если потом захотят 3 базу поддерживать то это будет закопаться.

Пару таких строк можешь показать? Хотя я давно не встречал запрос который не мог написать на linq2db.
Re[4]: Архитектура доступа к бд
От: BlackEric http://black-eric.lj.ru
Дата: 17.04.19 15:04
Оценка:
Здравствуйте, Danchik, Вы писали:


D>Пару таких строк можешь показать? Хотя я давно не встречал запрос который не мог написать на linq2db.


Там их сотни. ОТ простых до очень сложных агрегирующих выборок.
https://github.com/BlackEric001
Re[3]: Архитектура доступа к бд
От: · Великобритания  
Дата: 17.04.19 15:16
Оценка: +1
Здравствуйте, BlackEric, Вы писали:

BE>·>DAO же, классика.

BE>·>Притом рефакторинг вполне очевидный — вначале выделить слой Dao с единственной имплементацией Mssql, потом потихоньку начать создавать Psql и заменять реализацию.
BE>Да, DAO выделяться будет.
BE>Я вот думаю может работу с PostgreSql писать на linq2db, а потом все заменить на нее, потому что если потом захотят 3 базу поддерживать то это будет закопаться.
Ну пиши Linq2DbUserDao вместо PsqlUserDao Или хоть все сразу. Или можно даже некоторые вызовы из PsqlUserDao делегировать в Linq2DbUserDao и т.п.
Суть лишь в том, что вместо if-else — ООП.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 15:25
Оценка: 8 (2)
Здравствуйте, BlackEric, Вы писали:

BE>Здравствуйте, Danchik, Вы писали:



D>>Пару таких строк можешь показать? Хотя я давно не встречал запрос который не мог написать на linq2db.


BE>Там их сотни. ОТ простых до очень сложных агрегирующих выборок.


Берешь Linqer ну и причесываешь в конце.
А сложные аггригирующие выборки — это то на что linq2db заточен.
Re: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 15:40
Оценка: 1 (1)
BE>Какие еще есть варианты?

https://docs.microsoft.com/ru-ru/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
Только EntityFramework не обязательно можно обычные запросы.


public class FooDto
{
    public  Id {get;}
    public  A {get;set;}
    public  B {get;set;}
}


public interface IFooRepository
{
     IEnumerable<FooDto>  GetItems( params );
     void UpdateItem(FooDto item);     
}

public MsSqlRepository : IFooRepository
{
    //... специфика работы с MsSql
}

public PostgresRepository : IFooRepository
{
    //... специфика работы с Postgres
}



везде в коде используешь IFooRepository где нужно работать с Foo.
IFooRepository получаешь через Dependency Injection или если не хочется то крайний вариант
public static Dependencies
{

    // делаешь любым удобным способом переключение с MsSql реализации на Postgres
    public static IFooRepository FooRepository =>  new MsSqlRepository(connectionString);
                                                   //new PostgresRepository(connectionString);
}

// далее работаешь с FooRepository через интерфейс
Dependencies.FooRepository.GetItems();
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 17.04.2019 15:42 okon . Предыдущая версия .
Re[2]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 15:53
Оценка: +1 -1
Здравствуйте, okon, Вы писали:


BE>>Какие еще есть варианты?


O>https://docs.microsoft.com/ru-ru/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

O>Только EntityFramework не обязательно можно обычные запросы.

[Skip]

А вот патерн репозиторий я никому не рекомендую. Лишняя абстракция над базой. У вас уже есть EF — абстракция над базой.
Сидишь клепаешь Generic Repository потом Non-Generic Repostory. Потом пробуешь скрестить данные из двух репозиториев — и тут получается офигенно замоканный тормознутый солюшин.

Да в принципе уже разжевывали
http://rsdn.org/forum/dotnet/6872836.flat#6872836
Автор: Spinifex
Дата: 14.08.17
Re[3]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 16:03
Оценка:
D>А вот патерн репозиторий я никому не рекомендую. Лишняя абстракция над базой. У вас уже есть EF — абстракция над базой.

Не совсем, если достаточно EF, то да, можно не делать.
Но во всех остальных случаях либо EF не достаточно или для данной СУБД не реализован,
например для Oracle запросы приходится писать в ручную, т.к. то что генерит EF нормально работать может только на простых или маленьких базах.

На практике ничего лучше работы с OracleConnection/OracleCommand не обнаружил.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[4]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 16:08
Оценка:
Здравствуйте, okon, Вы писали:

D>>А вот патерн репозиторий я никому не рекомендую. Лишняя абстракция над базой. У вас уже есть EF — абстракция над базой.


O>Не совсем, если достаточно EF, то да, можно не делать.

O>Но во всех остальных случаях либо EF не достаточно или для данной СУБД не реализован,
O>например для Oracle запросы приходится писать в ручную, т.к. то что генерит EF нормально работать может только на простых или маленьких базах.

O>На практике ничего лучше работы с OracleConnection/OracleCommand не обнаружил.


Ну вот представь себе что я уже пару лет не писал запросы в коде вручную. Все прекрастно генерит linq2db.
То что EF к ним плохо заточен — это спасибо его дизайну и молодости EF Core. Про EF 6 я вообще молчу, да это ужас.
Re[5]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 16:17
Оценка:
O>>На практике ничего лучше работы с OracleConnection/OracleCommand не обнаружил.

D>Ну вот представь себе что я уже пару лет не писал запросы в коде вручную. Все прекрастно генерит linq2db.

D>То что EF к ним плохо заточен — это спасибо его дизайну и молодости EF Core. Про EF 6 я вообще молчу, да это ужас.

А какая СУБД ? Размеры таблиц ?

Тут важно что плохо заточен, не так важно почему именно,
поэтому любое более менее сложное и высоконагруженное решение потребует ухода от EF.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[6]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 16:24
Оценка:
Здравствуйте, okon, Вы писали:

O>>>На практике ничего лучше работы с OracleConnection/OracleCommand не обнаружил.


D>>Ну вот представь себе что я уже пару лет не писал запросы в коде вручную. Все прекрастно генерит linq2db.

D>>То что EF к ним плохо заточен — это спасибо его дизайну и молодости EF Core. Про EF 6 я вообще молчу, да это ужас.

O>А какая СУБД ? Размеры таблиц ?


Любая из 10+ поддерживаемых (уже и сам не помню сколько их)
Размеры таблиц тут как бы не релевантны. Генерится оптимальный сиквел, а уж как ты индексы настроил — сам себе буратино.

O>Тут важно что плохо заточен, не так важно почему именно,

O>поэтому любое более менее сложное и высоконагруженное решение потребует ухода от EF.

Так давно и ушел, когда понял что вся прелесть linq была уничтожена горе решениями.
Re[7]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 16:41
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, okon, Вы писали:


O>>>>На практике ничего лучше работы с OracleConnection/OracleCommand не обнаружил.


D>>>Ну вот представь себе что я уже пару лет не писал запросы в коде вручную. Все прекрастно генерит linq2db.

D>>>То что EF к ним плохо заточен — это спасибо его дизайну и молодости EF Core. Про EF 6 я вообще молчу, да это ужас.

O>>А какая СУБД ? Размеры таблиц ?


D>Любая из 10+ поддерживаемых (уже и сам не помню сколько их)

D>Размеры таблиц тут как бы не релевантны. Генерится оптимальный сиквел, а уж как ты индексы настроил — сам себе буратино.
Релевантны, потому что таблицы с 10 000 записей работать будут нормально как правило и без индексов.
В более менее промышленых решениях которые я встречал там от 100+ таблиц
Также от 1+ млн записей, в памяти таблицы не помещаются, индексы по всем вариантам фильтров не построишь.

p.s. да кстати мы говорим сейчас об архитектуре, так вот что касается всякий внешних библиотек,
типа linq2db и др, в хорошей архитектуре есть рекомендации делать прослойку типа ILinqToDB для того чтобы можно было
легче в будущем избавиться от конкретной библиотеки и использовать другую, особенно когда спецификой этой библиотеки начинает обрастать решение.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 17.04.2019 16:46 okon . Предыдущая версия .
Re[8]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 16:50
Оценка:
Здравствуйте, okon, Вы писали:

[skip]

D>>Любая из 10+ поддерживаемых (уже и сам не помню сколько их)

D>>Размеры таблиц тут как бы не релевантны. Генерится оптимальный сиквел, а уж как ты индексы настроил — сам себе буратино.
O>Релевантны, потому что таблицы с 10 000 записей работать будут нормально как правило и без индексов.
O>В более менее промышленых решениях которые я встречал там от 100+ таблиц
O>Также от 1+ млн записей, в памяти таблицы не помещаются, индексы по всем вариантам фильтров не построишь.

Извините, мы не дизайн базы обговариваем, а способ доступа к ним. Среди пользователей linq2db есть и такие кто говорит об 1000+ таблиц и никто еще на скорость не жаловался.

Какой же умник будет миллионы записей на клиент тянуть? Зачем?

Балк удаления, апдейты и вставки присутствуют, работа со времерными таблицами есть, оконные функции присутствуют, CTE из каробки, самый быстрый маппер на рынке. Мне достаточно.
Re[9]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 17:08
Оценка:
Здравствуйте, Danchik, Вы писали:

D>Здравствуйте, okon, Вы писали:


D>[skip]


D>>>Любая из 10+ поддерживаемых (уже и сам не помню сколько их)

D>>>Размеры таблиц тут как бы не релевантны. Генерится оптимальный сиквел, а уж как ты индексы настроил — сам себе буратино.
O>>Релевантны, потому что таблицы с 10 000 записей работать будут нормально как правило и без индексов.
O>>В более менее промышленых решениях которые я встречал там от 100+ таблиц
O>>Также от 1+ млн записей, в памяти таблицы не помещаются, индексы по всем вариантам фильтров не построишь.

D>Извините, мы не дизайн базы обговариваем, а способ доступа к ним. Среди пользователей linq2db есть и такие кто говорит об 1000+ таблиц и никто еще на скорость не жаловался.

дело не в 1000+ таблицах а количестве записей.
Но в целом 1000+ таблиц реальной базы ( как правило там и данных будет 1млн+ ) если покажете бенчмарки для linq2db как он справляется автогенеренными запросами, было бы интересно.
Если конечно это не для красного словца сказано.

D>Какой же умник будет миллионы записей на клиент тянуть? Зачем?

Так никто обычно и не тянет миллионы на клиент, но в базе чтобы отфильтровать нужные данные вам придется по этим миллионам пройтись как-то.
При это СУБД всю таблицу к себе в память поместить не может, а также нет возможности по всем кейсами индексы сделать их просто будет миллионы и будет тормозить вставку данных.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 17.04.2019 17:12 okon . Предыдущая версия .
Re[10]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 17:15
Оценка:
Здравствуйте, okon, Вы писали:

[skip]

D>>Извините, мы не дизайн базы обговариваем, а способ доступа к ним. Среди пользователей linq2db есть и такие кто говорит об 1000+ таблиц и никто еще на скорость не жаловался.

O>дело не в 1000+ таблицах а количестве записей.
O>Но в целом 1000+ таблиц если покажете бенчмарки для linq2db как он справляется автогенеренными запросами, было бы интересно.
O>Если конечно это не для красного словца сказано.

Там говорилось о чем-то страшном, сори концы искать нету времени.

D>>Какой же умник будет миллионы записей на клиент тянуть? Зачем?

O>Так никто обычно и не тянет миллионы на клиент, но в базе чтобы отфильтровать нужные данные вам придется по этим миллионам пройтись как-то.
O>При это СУБД всю таблицу к себе в память поместить не может, а также нет возможности по всем кейсами индексы сделать их просто будет миллионы и будет тормозить вставку данных.

Опять же мы не дизайн базы обговариваем. Если ощутимый прогиб в скоросоти — анализируйте план.
Вы же сиквелы ручками пишете, так вот на linq2db их можно писать точно так же один в один, но имея типобезопасный linq и query decomposition по умолчанию, просто используйте IQueryable.
Re[11]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 17:32
Оценка: -1
D>Опять же мы не дизайн базы обговариваем. Если ощутимый прогиб в скоросоти — анализируйте план.
D>Вы же сиквелы ручками пишете, так вот на linq2db их можно писать точно так же один в один, но имея типобезопасный linq и query decomposition по умолчанию, просто используйте IQueryable.
А как там оракловые хинты к запросу указать ?

Вот например
https://docs.oracle.com/cd/B12037_01/server.101/b10752/hintsref.htm

SELECT /*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
           USE_MERGE(j) FULL(j) */
    e1.first_name, e1.last_name, j.job_id, sum(e2.salary) total_sal
  FROM employees e1, employees e2, job_history j
  WHERE e1.employee_id = e2.manager_id
    AND e1.employee_id = j.employee_id
    AND e1.hire_date = j.start_date
  GROUP BY e1.first_name, e1.last_name, j.job_id
  ORDER BY total_sal;


Как этот запрос описать на linq2db
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Re[12]: Архитектура доступа к бд
От: Danchik Украина  
Дата: 17.04.19 18:17
Оценка:
Здравствуйте, okon, Вы писали:

D>>Опять же мы не дизайн базы обговариваем. Если ощутимый прогиб в скоросоти — анализируйте план.

D>>Вы же сиквелы ручками пишете, так вот на linq2db их можно писать точно так же один в один, но имея типобезопасный linq и query decomposition по умолчанию, просто используйте IQueryable.
O>А как там оракловые хинты к запросу указать ?

O>Вот например

O>https://docs.oracle.com/cd/B12037_01/server.101/b10752/hintsref.htm

O>
O>SELECT /*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
O>           USE_MERGE(j) FULL(j) */
O>    e1.first_name, e1.last_name, j.job_id, sum(e2.salary) total_sal
O>  FROM employees e1, employees e2, job_history j
O>  WHERE e1.employee_id = e2.manager_id
O>    AND e1.employee_id = j.employee_id
O>    AND e1.hire_date = j.start_date
O>  GROUP BY e1.first_name, e1.last_name, j.job_id
O>  ORDER BY total_sal;
O>


O>Как этот запрос описать на linq2db


Ну что же, попал. Для SQL Serevr мы это поддержали, часик и такой вариант без проблем для оракла. Необходимости небыло.

Что-то типа (можно и поприятней подход придумать):
using (var db = new DataConnection())
{
   db.StatementHints.Add(@"/*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
           USE_MERGE(j) FULL(j) */");

   var query = from e1 in db.GetTable<Employee>()
               from e2 in db.GetTable<Employee>().InnerJoin(e2 => e2.ManagerId == e1.EmployeeId)
               from j  in db.GetTable<JobHitory>().InnerJoin(j => j.EmployeeId == e1.EmployeeId && j.StartDate == e1.HireDate)
               group new {e1, e2} by new { e1.FirstName, e1.LastName, j.JobId } into g
               select new 
               {
                  g.Key.FirstName,    
                  g.Key.LastName,    
                  g.Key.JobId,
                  TotalSal = g.Sum(e => e.e2.Salary)
               };
    query = query.OrderBy(e => e. TotalSal);
    var result = query.ToList();
}
Re[13]: Архитектура доступа к бд
От: okon  
Дата: 17.04.19 18:39
Оценка:
D>Что-то типа (можно и поприятней подход придумать):
D>
D>using (var db = new DataConnection())
D>{
D>   db.StatementHints.Add(@"/*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
D>           USE_MERGE(j) FULL(j) */");
D>}
D>


Но в этом случае ты как раз теряешь то с чего начиналась тема , что эта прослойка заменяет абстракцию IRepository.
Тут ты указал специфику Оракла и этот же код нельзя будет также использовать на MSSQL.
Т.е. потребуется как минимум 2 реализации : с хинтами для оракла, с хинтами для mssql, а в реальной жизни скорее всего не только хинты но и сами запросы немного будут разные для разных СУБД
если придется оптимизировать.


Второй момент — особенности специфичные функции Oracle, например использование Sequence, как написать например
select schema.sequence.NEXTVAL from dual;
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Отредактировано 17.04.2019 18:40 okon . Предыдущая версия . Еще …
Отредактировано 17.04.2019 18:39 okon . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.