powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
19 сообщений из 19, страница 1 из 1
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021190
__Pavel__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Доброго времени суток!

Как я понял, передать Expression от клиента сервису очень трудно и иногда даже опасно в плане стабильности работы сервиса.
Но как быть с фильтрами? Например, когда необходимо отфильтровать возвращаемые сервисом данные по нескольким параметрам. Это легко сделать на стороне клиента, но это негативно скажется на производительности, а при условии что записей очень много - это просто недопустимо. Следовательно, фильтровать данные необходимо в момент их получения из базы (да я Кэп).

Я сделал такой вариант:
"Сущности"
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
namespace Model
{
    public class MyContext : DbContext
    {
        public MyContext() : base("MyContext") { }

        public DbSet<UserType> UserTypes { get; set; }
        public DbSet<UserStatus> UserStatuses { get; set; }
        public DbSet<UserSex> UserSexes { get; set; }
        public DbSet<User> Users { get; set; }
    }

    [DataContract(IsReference = true)]
    public class UserSex
    {
        [DataMember]
        public int UserSexID { get; set; }
        [DataMember]
        public string UserSexName { get; set; }
        [DataMember]
        public string UserSexShortName { get; set; }

        [DataMember]
        public virtual List<User> Users { get; set; } = new List<User>();

        public UserSex() { }
        public UserSex(string p_Name, string p_ShortName) { UserSexName = p_Name; UserSexShortName = p_ShortName; }
        public override string ToString() => UserSexName;
        public string ToShortString() => UserSexShortName;
    }

    [DataContract(IsReference = true)]
    public class UserType
    {
        [DataMember]
        public int UserTypeID { get; set; }
        [DataMember]
        public string UserTypeName { get; set; }

        [DataMember]
        public virtual List<User> Users { get; set; } = new List<User>();

        public UserType() { }
        public UserType(string p_Name) { UserTypeName = p_Name; }
        public override string ToString() => UserTypeName;
    }

    [DataContract(IsReference = true)]
    public class UserStatus
    {
        [DataMember]
        public int UserStatusID { get; set; }
        [DataMember]
        public string UserStatusName { get; set; }

        [DataMember]
        public virtual List<User> Users { get; set; } = new List<User>();

        public UserStatus() { }
        public UserStatus(string p_Name) { UserStatusName = p_Name; }
        public override string ToString() => UserStatusName;
    }

    [DataContract(IsReference = true)]
    public class User
    {
        [DataMember]
        public int UserID { get; set; }
        [DataMember]
        public string Login { get; set; }
        [DataMember]
        public string Passowrd { get; set; }
        [DataMember]
        public string LastName { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public string MiddleName { get; set; }
        [DataMember]
        public DateTime Birthday { get; set; }
        [DataMember]
        public bool IsOnline { get; set; }

        [DataMember]
        public int UserSexID { get; set; }
        [DataMember]
        public virtual UserSex UserSex { get; set; }

        [DataMember]
        public int UserTypeID { get; set; }
        [DataMember]
        public virtual UserType UserType { get; set; }

        [DataMember]
        public int UserStatusID { get; set; }
        [DataMember]
        public virtual UserStatus UserStatus { get; set; }

        public User() { }
        public override string ToString() => $"{LastName} {Name[0]}.{MiddleName[0]}.";
    }
}


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
public int Users_GetList
            (
            out List<User> p_List, 
            int p_Count = 0, 
            int p_Page = 0, 
            int p_TypeID = 0, 
            int p_StatusID = 0, 
            int p_SexID = 0, 
            string p_Name = null
            )
        {
            p_List = new List<User>();

            int val = VALID(4, "Users_GetList"); // Функция проверки прав пользователя
            if (val < 0) { return val; } // Возвращение кода ошибки, если проверка не пройдена

            using (var DB = new MyContext())
            {
                DB.Configuration.LazyLoadingEnabled = false;
                DB.Configuration.ProxyCreationEnabled = false;

                IQueryable<User> q = DB.Users
                    .AsNoTracking()
                    .Include(i => i.UserType)
                    .Include(i => i.UserStatus)
                    .Include(i => i.UserSex);

                if (p_StatusID > 0) q = q.Where(i => i.UserStatusID == p_StatusID);
                if (p_TypeID > 0) q = q.Where(i => i.UserTypeID == p_TypeID);
                if (p_SexID > 0) q = q.Where(i => i.UserSexID == p_SexID);
                if (p_Name != null) q = q.Where(i => i.LastName.Contains(p_Name) || i.Name.Contains(p_Name) || i.MiddleName.Contains(p_Name));

                q = q.OrderBy(i => i.UserID);
                if (p_Count > 0 && p_Page > 0) q = q.Skip(p_Count * p_Page);
                if (p_Count > 0) q = q.Take(p_Count);

                p_List = q.ToList();
                return p_List.Count;
            }
        }



При таком подходе эту функцию можно будет использовать с любым набором допустимых фильтров, а на стороне сервиса будет генерироваться необходимый LINQ запрос.
Хотелось бы узнать мнение по данному подходу.
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021224
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
__Pavel__,
почему трудно и опасно?
все зависит о целей и задачи, я бы пошел еще дальше,
фильтровал не в момент получения данных из хранилища, а самим хранилищем ( посредством sql запроса)
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021291
__Pavel__
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в степи,

Где-то в степия бы пошел еще дальше, фильтровал ... самим хранилищем ( посредством sql запроса)

Так у меня так и получается... яж использую IQueryable<User>, это запрос с отложенным выполнением и он транслируется в SQL запрос именно в момент, когда я получаю список, вызывая метод q.ToList(), объединяя все фильтры, что я применил в один запрос, разве нет?

Я проверял значение переменной в момент выполнения, вот результат:
при вызове функции со всеми параметрами
Код: c#
1.
2.
3.
// S - прокси класс на стороне клиента
// lu - List<User> для возвращения ответа
S.Users_GetList(p_List: out lu, p_Count: 25, p_Page: 2, p_StatusID: 1, p_TypeID: 1, p_SexID: 1, p_Name: "Pav");


переменная q (см. в первом посте) транслируется вот в такой SQL запрос
SQL
Код: 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.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
{SELECT TOP (2) 
    [top].[UserID] AS [UserID], 
    [top].[Login] AS [Login], 
    [top].[Passowrd] AS [Passowrd], 
    [top].[LastName] AS [LastName], 
    [top].[Name] AS [Name], 
    [top].[MiddleName] AS [MiddleName], 
    [top].[Birthday] AS [Birthday], 
    [top].[IsOnline] AS [IsOnline], 
    [top].[UserSexID] AS [UserSexID], 
    [top].[UserTypeID] AS [UserTypeID], 
    [top].[UserStatusID] AS [UserStatusID], 
    [top].[UserTypeID1] AS [UserTypeID1], 
    [top].[UserTypeName] AS [UserTypeName], 
    [top].[UserStatusID1] AS [UserStatusID1], 
    [top].[UserStatusName] AS [UserStatusName], 
    [top].[UserSexID1] AS [UserSexID1], 
    [top].[UserSexName] AS [UserSexName], 
    [top].[UserSexShortName] AS [UserSexShortName]
    FROM ( SELECT [Project1].[UserID] AS [UserID], [Project1].[Login] AS [Login], [Project1].[Passowrd] AS [Passowrd], [Project1].[LastName] AS [LastName], 

[Project1].[Name] AS [Name], [Project1].[MiddleName] AS [MiddleName], [Project1].[Birthday] AS [Birthday], [Project1].[IsOnline] AS [IsOnline], [Project1].[UserSexID] 

AS [UserSexID], [Project1].[UserTypeID] AS [UserTypeID], [Project1].[UserStatusID] AS [UserStatusID], [Project1].[UserTypeID1] AS [UserTypeID1], [Project1].

[UserTypeName] AS [UserTypeName], [Project1].[UserStatusID1] AS [UserStatusID1], [Project1].[UserStatusName] AS [UserStatusName], [Project1].[UserSexID1] AS 

[UserSexID1], [Project1].[UserSexName] AS [UserSexName], [Project1].[UserSexShortName] AS [UserSexShortName]
        FROM ( SELECT 
            [Extent1].[UserID] AS [UserID], 
            [Extent1].[Login] AS [Login], 
            [Extent1].[Passowrd] AS [Passowrd], 
            [Extent1].[LastName] AS [LastName], 
            [Extent1].[Name] AS [Name], 
            [Extent1].[MiddleName] AS [MiddleName], 
            [Extent1].[Birthday] AS [Birthday], 
            [Extent1].[IsOnline] AS [IsOnline], 
            [Extent1].[UserSexID] AS [UserSexID], 
            [Extent1].[UserTypeID] AS [UserTypeID], 
            [Extent1].[UserStatusID] AS [UserStatusID], 
            [Extent2].[UserTypeID] AS [UserTypeID1], 
            [Extent2].[UserTypeName] AS [UserTypeName], 
            [Extent3].[UserStatusID] AS [UserStatusID1], 
            [Extent3].[UserStatusName] AS [UserStatusName], 
            [Extent4].[UserSexID] AS [UserSexID1], 
            [Extent4].[UserSexName] AS [UserSexName], 
            [Extent4].[UserSexShortName] AS [UserSexShortName]
            FROM    [Users] AS [Extent1]
            INNER JOIN [UserTypes] AS [Extent2] ON [Extent1].[UserTypeID] = [Extent2].[UserTypeID]
            INNER JOIN [UserStatus] AS [Extent3] ON [Extent1].[UserStatusID] = [Extent3].[UserStatusID]
            INNER JOIN [UserSexes] AS [Extent4] ON [Extent1].[UserSexID] = [Extent4].[UserSexID]
            WHERE ([Extent1].[UserStatusID] = @p__linq__0) AND ([Extent1].[UserTypeID] = @p__linq__1) AND ([Extent1].[UserSexID] = @p__linq__2) AND (([Extent1].

[LastName] LIKE @p__linq__3 ESCAPE N'~') OR ([Extent1].[Name] LIKE @p__linq__4 ESCAPE N'~') OR ([Extent1].[MiddleName] LIKE @p__linq__5 ESCAPE N'~'))
        )  AS [Project1]
        ORDER BY [Project1].[UserID] ASC
        OFFSET 2 ROWS 
    )  AS [top]}



Я не сильно разбираюсь в SQL но все равно понимаю, что там много лишнего нагорожено, самое главное с моей точки зрения - это то, что вот этот кусок кода из функции Users_GetList(***):
Код: c#
1.
2.
3.
4.
                if (p_StatusID > 0) q = q.Where(i => i.UserStatusID == p_StatusID);
                if (p_TypeID > 0) q = q.Where(i => i.UserTypeID == p_TypeID);
                if (p_SexID > 0) q = q.Where(i => i.UserSexID == p_SexID);
                if (p_Name != null) q = q.Where(i => i.LastName.Contains(p_Name) || i.Name.Contains(p_Name) || i.MiddleName.Contains(p_Name));


в итоге превратился в один WHERE, а не в несколько вложенных запросов чего я боялся...

Где-то в степия бы пошел еще дальше,
фильтровал не в момент получения данных из хранилища
Естественно я бы не стал тащить всю коллекцию и локально ее фильтровать, у меня есть совесть))

Поправьте меня если я ошибаюсь, я только начал писать большой проект, не хочу понять свою ошибку в конце...
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021299
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
__Pavel__Как я понял, передать Expression от клиента сервису очень трудно и иногда даже опасно в плане стабильности работы сервиса.

https://github.com/kendo-labs/dlinq-helpers

рекомендую изучить проект. всё делается легко и просто. какие хочешь фильтры, и не нужны эти заморочки с SQL.
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021302
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в степипосредством sql запроса

лично я как-то обходился :)

но иногда приходилось скрипя зубами обращаться к SQL, это поддержка легаси проекта на мудацком убожестве под названием "NHibernate", который не жуёт то, что EF щёлкает как орешки даже не моргая без всяких SQL-костылей в HBM-ках.
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021326
kmaw
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttмудацком убожестве под названием "NHibernate"

не, он прекрасен. и его возможности еще только допиливаются MS в EF
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021390
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,
когда я имел в виду sql я имел ввиду запрос на сервер данных, как он получен? или обходом дерева или канкатенакцией, без разницы
это было сказано в противовес автору - авторСледовательно, фильтровать данные необходимо в момент их получения из базы
судя по тому что автор написал он работает с c Linq to Object, код я его не смотрел, для меня это противоистественно, так как
вернулся на джаву.
зы Афтор - выражай мысли правильно а не вульгарно..
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021432
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
__Pavel__
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
public int Users_GetList
            (
            out List<User> p_List, 
            int p_Count = 0, 
            int p_Page = 0, 
            int p_TypeID = 0, 
            int p_StatusID = 0, 
            int p_SexID = 0, 
            string p_Name = null
            )        

Вместо кучи параметров тут удобно применить Parameter Object Pattern . Тогда, кроме всего прочего, параметры пэйджинга p_Count и p_Page можно будет вынести в базовый класс.
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021443
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kmawhVosttмудацком убожестве под названием "NHibernate"

не, он прекрасен. и его возможности еще только допиливаются MS в EF

это когда было? )))
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021447
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей К__Pavel__
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
public int Users_GetList
            (
            out List<User> p_List, 
            int p_Count = 0, 
            int p_Page = 0, 
            int p_TypeID = 0, 
            int p_StatusID = 0, 
            int p_SexID = 0, 
            string p_Name = null
            )        


Вместо кучи параметров тут удобно применить Parameter Object Pattern . Тогда, кроме всего прочего, параметры пэйджинга p_Count и p_Page можно будет вынести в базовый класс.

Query Object, (fluent) Query Builder, Specifications... вот это тру. Куча параметров и объект с параметрами -- устаревшие подходы, сложные в сопровождении и тестировании.
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021448
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в степикод я его не смотрел, для меня это противоистественно, так как
вернулся на джаву.
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021466
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttАлексей Кпропущено...
Вместо кучи параметров тут удобно применить Parameter Object Pattern . Тогда, кроме всего прочего, параметры пэйджинга p_Count и p_Page можно будет вынести в базовый класс.

Query Object, (fluent) Query Builder, Specifications... вот это тру. Куча параметров и объект с параметрами -- устаревшие подходы, сложные в сопровождении и тестировании.Не надо усложнять там, где не надо.
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021480
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КНе надо усложнять там, где не надо.

это давно стандарт разработки корпоративных приложений )
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021490
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttАлексей КНе надо усложнять там, где не надо.

это давно стандарт разработки корпоративных приложений )ГОСТ? ANSI? Давай номер стандарта.
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021506
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей КhVosttпропущено...


Query Object, (fluent) Query Builder, Specifications... вот это тру. Куча параметров и объект с параметрами -- устаревшие подходы, сложные в сопровождении и тестировании.Не надо усложнять там, где не надо.Впрочем, отдай наружу IQueryable, если хочешь универсальности, и не придётся тащить в современный проект устаревшие подходы вроде: "Query Object, (fluent) Query Builder, Specifications... вот это тру".
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021575
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей К,
отдай наружу IQueryable - опасно..
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021591
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в степиАлексей К,
отдай наружу IQueryable - опасно.. Specifications - это безопасно, ага... те же яйца, вид сбоку. Ну хочет если он, я-то тут причём?

Я за отдачу наружу Parameter Object-а, способного сериализоваться для передачи через WCF, WebAPI и т. п.
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021787
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в степиАлексей К,
отдай наружу IQueryable - опасно..

с какой кстати опасно? никогда не понимал, не понимаю и не буду понимать это глупой боязни... чё вы так трясётесь за этот IQueryable, это интерфейс, и ничего в нём опасного нет. это уже полностью готовый к употреблению универсальный, всем понимаемый, употребимый в пищу без прожёвывания Query Builder, на который можно повесить спецификации или сделать проекцию, и вообще что угодно. никаких проблем.
...
Рейтинг: 0 / 0
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
    #39021814
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,
гыгы это был троллинг )
...
Рейтинг: 0 / 0
19 сообщений из 19, страница 1 из 1
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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