powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / Как работать с БД ?
22 сообщений из 47, страница 2 из 2
Как работать с БД ?
    #39309062
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Классы можно вообще не генерить
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
using System;
using System.Data.SqlClient;
using Dapper;
using System.Linq;

namespace TestDapper {
	class Program {

		static void Main(string[] args) {
			var db = new SqlConnection("Data Source=127.0.0.1;Initial Catalog=MyDB;User ID=user;Password=password");
			var t = db.Query("select * from Test where Id = @Id", new { Id = 6 }).SingleOrDefault();
			Console.WriteLine(t.Id + " " + t.Text);
		}
	}
}


Dapper автоматом создает объект dynamic. Работать будет помедленнее, но это редко когда критично.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309125
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TАлексей Кпропущено...
Ну пиши LINQ запрос так, чтобы на выходе получался нужный план выполнения SQL запроса. Так говоришь, как будто при генерации SQL запросов используется генератор случайных чисел. :-)
Ну не всегда возможно. С LEFT JOIN все плохо, UNION не получилось заставить сделать.Вместо join обычно используются ассоциации. С union проблем никаких.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309128
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
Классы можно вообще не генерить
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
using System;
using System.Data.SqlClient;
using Dapper;
using System.Linq;

namespace TestDapper {
	class Program {

		static void Main(string[] args) {
			var db = new SqlConnection("Data Source=127.0.0.1;Initial Catalog=MyDB;User ID=user;Password=password");
			var t = db.Query("select * from Test where Id = @Id", new { Id = 6 }).SingleOrDefault();
			Console.WriteLine(t.Id + " " + t.Text);
		}
	}
}


Dapper автоматом создает объект dynamic. Работать будет помедленнее, но это редко когда критично.Критично отсутствие типизации при работе с данными, если использовать dynamic.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309198
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КDima Tпропущено...

Ну не всегда возможно. С LEFT JOIN все плохо, UNION не получилось заставить сделать.Вместо join обычно используются ассоциации. С union проблем никаких.
Пример, из недавнего.
таблицы:
Код: c#
1.
2.
3.
GroupAddr (Id, GroupId, AddrId) // Группы адресов
UserAddr (Id, UserId, AddrId, GroupAddrId) // Привязка юзера к адресам
Doc(Id, AddrId, ...) // Документы


Есть адреса и группы адресов. Юзер может быть привязан и к конкретному адресу, и к группе адресов.
Надо выбрать все документы по адресам юзера. В фильтре имеем только конкретный @UserId

В SQL просто пишется
Код: c#
1.
2.
3.
4.
select Id, AddrId, ... from Doc
    where AddrId in (
                select nAddrId from UserAddr where UserAddr.UserId = @UserId and UserAddr.nAddrId is not null
                  union select AddrId from UserAddr join GroupAddr on UserAddr.GroupAddrId = GroupAddr.Id where UserAddr.UserId = @UserId)



Заставить Linq выдать такой запрос я не смог. Вообще ничего не смог сделать чтобы обойтись одним обращением к серверу. Может конечно у меня опыта мало. Покажи как одним Linq запросом сделать тоже самое.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309199
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей ККритично отсутствие типизации при работе с данными, если использовать dynamic.
ИМХУ если запрос и обработка результата в пределах одного метода, то некритично. Если куда-то передавать, хранить, то согласен, надо сделать класс. В моем случае первое чаще: запросил из БД, сгенерил ответ, отправил.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309207
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Напутал немного
Код: c#
1.
2.
3.
GroupAddr (Id, GroupId, AddrId) // Группы адресов
UserAddr (Id, UserId, AddrId, GroupId) // Привязка юзера к адресам
Doc(Id, AddrId, ...) // Документы


Есть адреса и группы адресов. Юзер может быть привязан и к конкретному адресу, и к группе адресов.
Надо выбрать все документы по адресам юзера. В фильтре имеем только конкретный @UserId

Код: c#
1.
2.
3.
4.
select Id, AddrId, ... from Doc
    where AddrId in (
                select nAddrId from UserAddr where UserAddr.UserId = @UserId and UserAddr.nAddrId is not null
                  union select AddrId from UserAddr join GroupAddr on UserAddr.GroupId = GroupAddr.GroupId where UserAddr.UserId = @UserId)
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309208
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TАлексей Кпропущено...
Вместо join обычно используются ассоциации. С union проблем никаких.
Пример, из недавнего.
таблицы:
Код: c#
1.
2.
3.
GroupAddr (Id, GroupId, AddrId) // Группы адресов
UserAddr (Id, UserId, AddrId, GroupAddrId) // Привязка юзера к адресам
Doc(Id, AddrId, ...) // Документы


Есть адреса и группы адресов. Юзер может быть привязан и к конкретному адресу, и к группе адресов.
Надо выбрать все документы по адресам юзера. В фильтре имеем только конкретный @UserId

В SQL просто пишется
Код: c#
1.
2.
3.
4.
select Id, AddrId, ... from Doc
    where AddrId in (
                select nAddrId from UserAddr where UserAddr.UserId = @UserId and UserAddr.nAddrId is not null
                  union select AddrId from UserAddr join GroupAddr on UserAddr.GroupAddrId = GroupAddr.Id where UserAddr.UserId = @UserId)



Заставить Linq выдать такой запрос я не смог. Вообще ничего не смог сделать чтобы обойтись одним обращением к серверу. Может конечно у меня опыта мало. Покажи как одним Linq запросом сделать тоже самое.Вообще без проблем. Завтра постараюсь ответить. Сейчас нет возможности, пишу с мобилы.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309209
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TАлексей ККритично отсутствие типизации при работе с данными, если использовать dynamic.
ИМХУ если запрос и обработка результата в пределах одного метода, то некритично. Если куда-то передавать, хранить, то согласен, надо сделать класс. В моем случае первое чаще: запросил из БД, сгенерил ответ, отправил.Даже если в пределах одного метода, то удобнее использовать linq и анонимный класс.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309339
Фотография skyANA
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TskyANAА вообще меньше буков кода - это когда меньше всяких DTO, POCO, Business Objects, Services, Repositories, Mappers.
Если не злоупотреблять, то много не будет.
skyANAИ ещё ORM-ы бывают работают не так как вам надо, или не оптимально, или в них тупо баги и приходится писать код, чтобы это обойти.
Невозможно оптимально обернуть РСУБД с помощью ООП, но это не мешает в 99% случаев, в оставшемся 1% можно позаморачиваться с оптимизацией. Для простых запросов Linq генерит вполне нормальные select`ы, более сложные вещи можно вынести на сторону sql-сервера (писать ХП или view делать).
Багов хотелось бы поменьше, поэтому и хочу ширпотребное решение, чтобы баги по-максимуму уже были убраны.
С 99% - это Вы погорячились :)
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309385
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, Портировал твой запрос на LINQ, не вдаваясь в подробности. Могут быть ошибки, но принцип, думаю, понятен. Повторюсь, в реальной жизни join заменяется ассоциациями.

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
        var userId = 123;

        var q1 =
            from u in Db.UserAddr
            where u.UserId == userId && u.nAddrId.HasValue
            select u.AddrId;

        var q2 =
            from u in Db.UserAddr
            join g in Db.GroupAddr on u.GroupId equals g.GroupId
            where u.UserId == userId
            select u.AddrId;

        var q3 =
            from addrId in q1.Union(q2)
            join doc in Db.Doc on addrId equals doc.AddrId
            select doc;

        var result = q3.ToArray();
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309407
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КDima T, Портировал твой запрос на LINQ, не вдаваясь в подробности. Могут быть ошибки, но принцип, думаю, понятен. Повторюсь, в реальной жизни join заменяется ассоциациями.
Затестил, select не такой
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
SELECT
    [Extent4].[ID] AS [ID],
    [Extent4].[AddrID] AS [AddrID],
    [Extent4].[Text] AS [Text]
    FROM   (SELECT DISTINCT
        [UnionAll1].[AddrID] AS [C1]
        FROM  (SELECT
            [Extent1].[AddrID] AS [AddrID]
            FROM [dbo].[UserAddr] AS [Extent1]
            WHERE ([Extent1].[UserID] = @p__linq__0) AND ([Extent1].[AddrID] IS NOT NULL)
        UNION ALL
            SELECT
            [Extent2].[AddrID] AS [AddrID]
            FROM  [dbo].[UserAddr] AS [Extent2]
            INNER JOIN [dbo].[GroupAddr] AS [Extent3] ON [Extent2].[GroupID] = [Extent3].[GroupID]
            WHERE [Extent2].[UserID] = @p__linq__1) AS [UnionAll1] ) AS [Distinct1]
    INNER JOIN [dbo].[Doc] AS [Extent4] ON [Distinct1].[C1] = [Extent4].[AddrID]
-- p__linq__0: '123' (Type = Int32, IsNullable = false)
-- p__linq__1: '123' (Type = Int32, IsNullable = false)


Тут where ... in заменен на join поэтому пришлось обернуть union в select distinct, т.е. лишний вложенный запрос.
На плане видно что лишний select вызвал лишние операции.
План выполнения, сверху мой запрос, снизу Linq

В цифрах Estimated Subtree Cost (суммарная стоимость всех операций) такая
Запрос Значениемой0.0065717 linq0.0278751
Пропорции тут нет смысла считать, т.к. таблицы пустые.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309434
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TТут where ... in заменен на joinДа заменён, но это принципиально ничего не меняет. Можно заменить на вложенный запрос в разделе where, но мне в данном случае join нравится больше. Но если там план выполнения плохой, то точно не из-за этого.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309437
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TВ цифрах Estimated Subtree Cost (суммарная стоимость всех операций) такая
Запрос Значениемой0.0065717 linq0.0278751
Пропорции тут нет смысла считать, т.к. таблицы пустые.Ну и какой смысл сравнивать статистику выполнения запросов на пустых таблицах?
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309440
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TНа плане видно что лишний select вызвал лишние операции.Твой запрос не возвращает поле Doc.Text. Вероятно, причина в этом.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309452
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КDima TНа плане видно что лишний select вызвал лишние операции.Твой запрос не возвращает поле Doc.Text. Вероятно, причина в этом.
Возвращает, я добавил, на картинке с планом видно текст запроса.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309457
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

Ну напиши так, для чистоты эксперимента:
Код: c#
1.
2.
3.
4.
var q3 =
    from doc in Db.Doc
    where q1.Union(q2).Any(addrId  => addrId == doc.AddrId)
    select doc;



Но я в этом смысла не вижу.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309469
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КНу и какой смысл сравнивать статистику выполнения запросов на пустых таблицах?
Замерил на рабочей базе, там правда записей пока не много (GroupAddr 473, UserAddr 3, Doc 4018)

ЗапросЗначениемой0.0763995linq0.0896945
быстрее на 17%
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309475
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КDima T,

Ну напиши так, для чистоты эксперимента:
Код: c#
1.
2.
3.
4.
var q3 =
    from doc in Db.Doc
    where q1.Union(q2).Any(addrId  => addrId == doc.AddrId)
    select doc;



Но я в этом смысла не вижу.
текст запроса
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
SELECT
    [Extent1].[ID] AS [ID],
    [Extent1].[AddrID] AS [AddrID],
    [Extent1].[Text] AS [Text]
    FROM [dbo].[Doc] AS [Extent1]
    WHERE  EXISTS (SELECT
        1 AS [C1]
        FROM ( SELECT DISTINCT
            [UnionAll1].[AddrID] AS [C1]
            FROM  (SELECT
                [Extent2].[AddrID] AS [AddrID]
                FROM [dbo].[UserAddr] AS [Extent2]
                WHERE ([Extent2].[UserID] = @p__linq__0) AND ([Extent2].[AddrID] IS NOT NULL)
            UNION ALL
                SELECT
                [Extent3].[AddrID] AS [AddrID]
                FROM  [dbo].[UserAddr] AS [Extent3]
                INNER JOIN [dbo].[GroupAddr] AS [Extent4] ON [Extent3].[GroupID] = [Extent4].[GroupID]
                WHERE [Extent3].[UserID] = @p__linq__1) AS [UnionAll1]
        )  AS [Distinct1]
        WHERE [Distinct1].[C1] = [Extent1].[AddrID]
    )
-- p__linq__0: '123' (Type = Int32, IsNullable = false)
-- p__linq__1: '123' (Type = Int32, IsNullable = false)


Так быстрее, план почти такой же как у меня, и время соответственно такое же 0.0065719
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309492
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ok
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309680
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

Напоследок, тут distinct не нужен. Можно заменить Union на Concat. План должен стать лучше.
Код: c#
1.
2.
3.
4.
var q3 =
    from doc in Db.Doc
    where q1.Concat(q2).Any(addrId => addrId == doc.AddrId)
    select doc;
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309701
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КDima T,

Напоследок, тут distinct не нужен. Можно заменить Union на Concat. План должен стать лучше.
Код: c#
1.
2.
3.
4.
var q3 =
    from doc in Db.Doc
    where q1.Concat(q2).Any(addrId => addrId == doc.AddrId)
    select doc;


запрос
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
SELECT
    [Extent1].[ID] AS [ID],
    [Extent1].[AddrID] AS [AddrID],
    [Extent1].[Text] AS [Text]
    FROM [dbo].[Doc] AS [Extent1]
    WHERE  EXISTS (SELECT
        1 AS [C1]
        FROM  (SELECT
            [Extent2].[AddrID] AS [AddrID]
            FROM [dbo].[UserAddr] AS [Extent2]
            WHERE ([Extent2].[UserID] = @p__linq__0) AND ([Extent2].[AddrID] IS NOT NULL)
        UNION ALL
            SELECT
            [Extent3].[AddrID] AS [AddrID]
            FROM  [dbo].[UserAddr] AS [Extent3]
            INNER JOIN [dbo].[GroupAddr] AS [Extent4] ON [Extent3].[GroupID] = [Extent4].[GroupID]
            WHERE [Extent3].[UserID] = @p__linq__1) AS [UnionAll1]
        WHERE [UnionAll1].[AddrID] = [Extent1].[AddrID]
    )
-- p__linq__0: '123' (Type = Int32, IsNullable = false)
-- p__linq__1: '123' (Type = Int32, IsNullable = false)


План стал один-в-один как у меня, время тоже сравнялось 0.0065717.
...
Рейтинг: 0 / 0
Как работать с БД ?
    #39309705
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ok
...
Рейтинг: 0 / 0
22 сообщений из 47, страница 2 из 2
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / Как работать с БД ?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]