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

Как я понял, передать 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
02.08.2015, 17:52
    #39021224
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
__Pavel__,
почему трудно и опасно?
все зависит о целей и задачи, я бы пошел еще дальше,
фильтровал не в момент получения данных из хранилища, а самим хранилищем ( посредством sql запроса)
...
Рейтинг: 0 / 0
02.08.2015, 20:43
    #39021291
__Pavel__
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
Где-то в степи,

Где-то в степия бы пошел еще дальше, фильтровал ... самим хранилищем ( посредством 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
02.08.2015, 21:08
    #39021299
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
__Pavel__Как я понял, передать Expression от клиента сервису очень трудно и иногда даже опасно в плане стабильности работы сервиса.

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

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

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

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

не, он прекрасен. и его возможности еще только допиливаются MS в EF
...
Рейтинг: 0 / 0
03.08.2015, 07:39
    #39021390
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
hVostt,
когда я имел в виду sql я имел ввиду запрос на сервер данных, как он получен? или обходом дерева или канкатенакцией, без разницы
это было сказано в противовес автору - авторСледовательно, фильтровать данные необходимо в момент их получения из базы
судя по тому что автор написал он работает с c Linq to Object, код я его не смотрел, для меня это противоистественно, так как
вернулся на джаву.
зы Афтор - выражай мысли правильно а не вульгарно..
...
Рейтинг: 0 / 0
03.08.2015, 09:40
    #39021432
Алексей К
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
__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
03.08.2015, 09:50
    #39021443
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
kmawhVosttмудацком убожестве под названием "NHibernate"

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

это когда было? )))
...
Рейтинг: 0 / 0
03.08.2015, 09:53
    #39021447
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
Алексей К__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
03.08.2015, 09:54
    #39021448
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
Где-то в степикод я его не смотрел, для меня это противоистественно, так как
вернулся на джаву.
...
Рейтинг: 0 / 0
03.08.2015, 10:21
    #39021466
Алексей К
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
WCF + EF, функция с параметрами вместо IQueryable, хороший ли подход?
hVosttАлексей Кпропущено...
Вместо кучи параметров тут удобно применить Parameter Object Pattern . Тогда, кроме всего прочего, параметры пэйджинга p_Count и p_Page можно будет вынести в базовый класс.

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

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

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


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

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

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


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