LINQ to SQL. первые разочарования.
От: снежок Россия  
Дата: 10.12.07 08:31
Оценка: 3 (1) -1
Вот на днях решил опробовать LINQ to SQL в VS 2008...
Создал простенькую базу для теста.

Основная цель была проверка маппинга на хранимые процедуры и корректной реализации/настройки наследования.
Не знаю как для кого, но для меня теоритически существует два нормальных вида реализции наследования в БД (хотя многие не любят применять этот термин относительно БД).
1 — это реализация наследования в виде связи 1-к-1 (атрибуты родительского класса не дублируются в производных)
2 — дублирование атрибутов родительского класса в производных.
Часто с успехом мне удается комбинировать эти два подхода в целях оптимизации работы БД.
Другие подходы, по типу "столбец-идентификатор типа" и спихивание всех атрибутов всех типов в одну таблицу считаю вариациями плохого проектирования или анализа, EAV — отдельная тема.

Маппинг на хп действительно оказался возможным, что очень порадовало, при этом настройка маппинга сделана удобной и гибкой.
Однако, что касается наследования — полный отстой.
То что нам предлагается в этом плане — это Single-table inheritance.
Вы настраиваете base-class, указывая свойство-идентификатор типа на основе которого LINQ определяет какой тип объекта будет создан для каждого экземпляра при запросе всей коллекции базового типа. При этом, похоже, что на уровне БД у вас нет возможности разнести производные классы по таблицам, т.е. все атрибуты всех классов должны лежать в одной таблице(или же должна использоваться view), а на уровне dbml-разметки определяется какие атрибуты к какому классу относятся.
Для меня, например, это полный бред.
Потом, в коде нет возможности поместить экземпляр производного типа в свою же типизированную коллекцию. Вы можете поместить экземпляр производного типа только в коллекцию базового типа. Коллекции для производных типов просто не генерятся. Т.е. нет возможности сделать DataContext.DerivedClassList.InsertOnSubmit(derivedInstance);
Возможно только DataContext.BaseClassList.InsertOnSubmit(derivedInstance); но при этом, когда происходит SubmitChanges() производится маппинг на методы (хп) базового типа.

Вот что по этому поводу написано в MSDN:
The Object Relational Designer (O/R Designer) supports the concept of single-table inheritance as it is often implemented in relational systems. In single-table inheritance, there is a single database table that contains fields for both parent information and child information.

Это где это они такой "often implemented" нашли ? Индусы что ли замучали?
При этом multi-table inheritance они обещали сделать в релизе, еще когда появился августовский CTP...

Вообщем, как ORM продукт для меня оказался достаточно сыроват. Посмотрим, может быть что то измениться в будущем, а пока в сторону, обойдемся. Да и прочие поставщики субд (oracle...) смотрю, как то без особой эйфории отнеслись к linq, не спешат они делать реализации его под свои субд...
Re: LINQ to SQL. первые разочарования.
От: stump http://stump-workshop.blogspot.com/
Дата: 10.12.07 09:29
Оценка: 1 (1) +2
Здравствуйте, снежок, Вы писали:

С>Вообщем, как ORM продукт для меня оказался достаточно сыроват. Посмотрим, может быть что то измениться в будущем, а пока в сторону, обойдемся. Да и прочие поставщики субд (oracle...) смотрю, как то без особой эйфории отнеслись к linq, не спешат они делать реализации его под свои субд...


LINQ to SQL не позиционируется как полноценный ORM framework.
Дождитесь выхода ADO.NET Entity Framework в феврале. Там будет все что вам необходимо (в частности по маппингу и наследованию все ваши вопросы решаются там элементарно).
Понедельник начинается в субботу
Re[2]: LINQ to SQL. первые разочарования.
От: снежок Россия  
Дата: 10.12.07 09:42
Оценка:
S>LINQ to SQL не позиционируется как полноценный ORM framework.
S>Дождитесь выхода ADO.NET Entity Framework в феврале. Там будет все что вам необходимо (в частности по маппингу и наследованию все ваши вопросы решаются там элементарно).

Очень надеюсь что решатся.
Ну а как тогда позиционируется LINQ to SQL? Полноценным маппинг-хелпером его тоже не назовешь...
Re[3]: LINQ to SQL. первые разочарования.
От: stump http://stump-workshop.blogspot.com/
Дата: 10.12.07 09:47
Оценка: +1
Здравствуйте, снежок, Вы писали:

С>Ну а как тогда позиционируется LINQ to SQL? Полноценным маппинг-хелпером его тоже не назовешь...


Позиционируется как:

LINQ to SQL: .NET Language-Integrated Query for Relational Data

(выделение мое)
Ключевые слова здесь "Language-Integrated" и "Relational Data"
Понедельник начинается в субботу
Re: LINQ to SQL. первые разочарования.
От: vdimas Россия  
Дата: 10.12.07 11:55
Оценка:
Здравствуйте, снежок, Вы писали:

ORM и query-helper — это из разных опер вещи.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[2]: LINQ to SQL. первые разочарования.
От: снежок Россия  
Дата: 10.12.07 12:07
Оценка:
V>ORM и query-helper — это из разных опер вещи.
vdimas, я в курсе
Просто не понятно теперь становится вообще место LINQ to SQL.
Т.е. это сильно урезанная версия EDM для экспериментов на досуге?
Re[3]: LINQ to SQL. первые разочарования.
От: vdimas Россия  
Дата: 10.12.07 13:54
Оценка:
Здравствуйте, снежок, Вы писали:


С>Просто не понятно теперь становится вообще место LINQ to SQL.


Место простое — реализация провайдера, чтобы ты сам его не писал.

С>Т.е. это сильно урезанная версия EDM для экспериментов на досуге?


Да вот еще. Для нашей мини-ORM системы подобный провайдер позволит выкинуть самописный SQL-генератор и немного улучшить код, где мы генерируем объекты-запросы. Так же позволит выкинуть приличный код по маппингу, т.к. LINQ в этом плане тоже нехило помогает.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[3]: LINQ to SQL. первые разочарования.
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.12.07 16:12
Оценка: 2 (2) +3
Здравствуйте, снежок, Вы писали:

С>Просто не понятно теперь становится вообще место LINQ to SQL.

С>Т.е. это сильно урезанная версия EDM для экспериментов на досуге?

Есть мнение, что ООП с его догмами подходит для хранения и обработки данных несколько хуже чем SQL-РСУБД. LINQ to SQL — это средство не использоват мапинг, а работать с массивами данных напрямую. Объекты зедесь не более чем средство представления данных из БД. Именно по этому были введены анонимные типы. Они вообще прямое воплощение кортежа из реляционной логики.

ЗЫ

Не спеши возмущаться. Твое сознание зашорено теми догмами которые впишивали в него индустриальные проповедники. Возможно когда-то ты прицдешь к выводу, что O/R-маперы шаг в не верном направлении.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: LINQ to SQL. первые разочарования.
От: tripolox Россия  
Дата: 10.12.07 16:18
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Не спеши возмущаться. Твое сознание зашорено теми догмами которые впишивали в него индустриальные проповедники. Возможно когда-то ты прицдешь к выводу, что O/R-маперы шаг в не верном направлении.


Где же верное направление?
Re: LINQ to SQL. первые разочарования.
От: Igor Trofimov  
Дата: 10.12.07 18:40
Оценка:
С>Другие подходы, по типу "столбец-идентификатор типа" и спихивание всех атрибутов всех типов в одну таблицу считаю вариациями плохого проектирования или анализа

Ну, обоснуй что-ли для ясности
Заодно прикинь стоимость соединения таблиц, если, скажем, у тебя в иерархии пару миллионов записей, а отличающихся в потомках свойств — раз два и обчелся.
Re[2]: LINQ to SQL. первые разочарования.
От: снежок Россия  
Дата: 10.12.07 22:31
Оценка: -1
Здравствуйте, Igor Trofimov, Вы писали:

С>>Другие подходы, по типу "столбец-идентификатор типа" и спихивание всех атрибутов всех типов в одну таблицу считаю вариациями плохого проектирования или анализа


iT>Ну, обоснуй что-ли для ясности

Ванек Бодягин (IB) вон минусы ставит и ничего обосновывать или рассказать что то полезное (раз уж он такая звезда в LINQ) не стремиться
iT>Заодно прикинь стоимость соединения таблиц, если, скажем, у тебя в иерархии пару миллионов записей, а отличающихся в потомках свойств — раз два и обчелся.

Стоимость соединения я прикидываю на реальных данных в ходе внедрения или эксплуатации.
И если оно, соединение, становится слишком дорогим, то я легко рефакторю "тяжелые" таблицы ко второму варианту реализации наследования, когда атрибуты предка дублируются в атрибутах потомка. При этом связь 1-к-1 исчезает(удаляется). И так как работа с таблицами инкапсулирована в хп, то никакие слои кроме CRUD SPs и DB этот рефакторинг не задевает. Вообще эта задача может ложиться на администратора БД/тех. специалиста по обслуживанию, если четко прописать ему roadmap для подобных случаев.
На первоначальном этапе анализа и проектирования я никогда не заменяю наследование на атрибут-признак типа, так как с большой вероятностью на этом этапе может что то ускользнуть от твоего взгляда и при этом легко допустить ошибку проектирования.
Я всегда смогу вернуться к рефакторингу в направлении создания атрибута-признака типа на завершающих этапах, если это решение действительно окажется удовлетворительным. Яркий пример когда введение атрибута-признака типа очень часто является ошибкой — это "Физические лица и Юридические лица". Хороший пример когда стоит ввести такой атрибут — это "Балансовый и Забалансовый счет в бухучете" т.к. довольно сложно придумать как еще эти подтипы могут быть расширены.

А рассуждая так, что в потомках отличающихся свойств раз два и обчелся, недолго дойти и до решения когда всю базу можно уложить в одну таблицу. Хотя я конечно же уверен что к такому маразму ты никогда не стремился

P/S/
Кстати, нашел блог где достаточно хорошо расставлены точки над i и объясняется по поводу места Linq to sql и EDF:
здесь
Re[4]: LINQ to SQL. первые разочарования.
От: снежок Россия  
Дата: 10.12.07 22:43
Оценка: +1
VD>Есть мнение, что ООП с его догмами подходит для хранения и обработки данных несколько хуже чем SQL-РСУБД. LINQ to SQL — это средство не использоват мапинг, а работать с массивами данных напрямую. Объекты зедесь не более чем средство представления данных из БД.
VD>ЗЫ
VD>Не спеши возмущаться. Твое сознание зашорено теми догмами которые впишивали в него индустриальные проповедники. Возможно когда-то ты прицдешь к выводу, что O/R-маперы шаг в не верном направлении.

Скорее тут не направление может оказаться неправильным, а применение.
Просто существуют data-ориентированные системы/решение и решения где тяжеловато обойтись без разветвленных бизнес-классов. Вот, видимо, LINQ to SQL позиционируется как решение для data-ориентированных систем. И хотя EDF полностью покрывает по возможностям LINQ to SQL — это весьма далекие друг от друга продукты.

p/s/ спасибо за участие
Re[3]: LINQ to SQL. первые разочарования.
От: Sinix  
Дата: 11.12.07 08:32
Оценка: 23 (8)
Ну и мои 5 копеек. Сразу, чтоб не флеймить. Сам по себе LINQ — забавная идея. Но вот реализация...

Она дико сырая. Безумно раздражает, что вместо того, чтобы работать с сиквелом, который я знаю и понимаю, я должен работать с какой-то финтифлюшкой, которая изображает из себя сиквел, как его видят разработчики финтифлюшки. Плохо видят кстати. Меня задолбало пытаться написать LINQ-запрос так, чтоб он хотя бы примерно соответствовал тому, что должно быть и угадывать, как поведёт себя SelectMany в сочетании с GroupBy и GroupJoin (да, кстати, Left Join'a нет. Потомучта.). Задолбало разбираться, почему я должен править что-то в xml-х кишках этого чудо-монстра, чтобы наконец заработали хранимые процедуры, а потом материться и переписывать параметризованные функции на вьюхи, чтобды эта падла нормально загружала details'ы.

В общем жопа всё это. Впрочем, не меньшая, чем EF. Последнее вообще, по-моему, бред полный, ибо трактуется как средство для выноса концептуальной модели на сторону клиента. Афигеть, да? А сиквел у нас чем должен заниматься? Байтики хранить? А теперь учтите, что у нас не одно приложение базу юзает. И каждое должно видеть эту базу по-своему, и не лезть куда не положено, потому что в противном случае шеф собственноручно глубоко проинсталлирует в меня весь сервер. У каждого приложения должна быть своя концептуальная модель, да?)))

В общем от лукавого всё это...

Ндя. Обещал же. 5 копеек про LINQ for SQL.

1. Отсутствие отсоединённого режима работы.
Я до сих пор не могу понять, почему либо я использую SqlQuery<T> (или как его там...) и терплю непрекращаюшиеся обращения к серверу на каждый чих,
либо пытаюсь использовать EaferLoad с копированием загруженных элементов типа .ToBindingList() и натыкаюсь на весёлые грабли... Потому что EagerLoad тоже через попу работает))) Самое большее, что с его помощью можно добиться — чтобы загружались дети при обращении к родителю. В результате, если у вас 15 родительских записей, вам потребуется обратиться к серверу всего 15 раз. Мило, да?)
Если интересно — _тынц_ на пост из блога OakLeaf Systems (там есть ещё много таких граблей... читайте и обрящете дао), тынц августовский, но те же грабли наблюдаются и на релизе.

Да, многие-ко-многим — это тоже та ещё пестня... Но про это я рассказывать не буду — не хочу портить очучения.

2. Производительность. На эту тему даже рыдать не хочется. Я не могу понять, почему жалкие полтыщи master/details строк должны загружаться по три-пять секунд? Аналогичный штук с датаадаптером на порядок шустрее.

3. Lazy load. Ну вот раздражает меня тот факт, что результатом любого запроса могут быть устаревшие данные (не забываем, что все сущности весьма весело кэшируются внутри контекста). Даже если мне надо будет показывать лишь часть данных, я предпочту постраничную выборку. Потому что буду уверен, что все данные согласованы. И не буду гадать, сколько времени назад и что загрузилось.

4. Невозможность сериализации данных. Точнее так. Сериализовать их можно. А вот восстановить и определить какие данные надо вставить в БД, а какие не изменялись — хрен те. Официальный совет: восстанавливайте оригинальные версии и вносите все изменения заново. Опупеть, да?

5. Убогий сгенеренный код. Если начальство увидит, что код в продакшне обращается к серверу вот так (это для одного (!) родителя):
exec sp_executesql N'SELECT [t0].[OrderID], [t0].[CustomerID], 
  [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], 
  [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], 
  [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], 
  [t0].[ShipPostalCode], [t0].[ShipCountry], [t1].[OrderID] AS [OrderID2], 
  [t1].[ProductID], [t1].[UnitPrice], [t1].[Quantity], [t1].[Discount], (
    SELECT COUNT(*)
    FROM [dbo].[Order Details] AS [t2]
    WHERE [t2].[OrderID] = [t0].[OrderID]
    ) AS [count]
    FROM [dbo].[Orders] AS [t0]
    LEFT OUTER JOIN [dbo].[Order Details] AS [t1] 
      ON [t1].[OrderID] = [t0].[OrderID]
    WHERE [t0].[CustomerID] = @x1
    ORDER BY [t0].[OrderID], [t1].[ProductID]',N'@x1 nchar(5)',@x1=N'ALFKI'

или не дай бог вот так (типа EagerLoad, как добиться — см здесь):
SELECT COUNT(*) AS [value]
FROM [dbo].[Orders] AS [t0]
LEFT OUTER JOIN [dbo].[Customers] AS [t1] 
    ON [t1].[CustomerID] = [t0].[CustomerID]
LEFT OUTER JOIN [dbo].[Employees] AS [t2] 
    ON [t2].[EmployeeID] = [t0].[EmployeeID]
LEFT OUTER JOIN [dbo].[Shippers] AS [t3] ON [t3].[ShipperID] = [t0].[ShipVia]

exec sp_executesql N'SELECT TOP 15 [t7].[OrderID], [t7].[CustomerID], 
  [t7].[EmployeeID], [t7].[OrderDate], [t7].[RequiredDate], 
  [t7].[ShippedDate], [t7].[ShipVia], [t7].[Freight], [t7].[ShipName], 
  [t7].[ShipAddress], [t7].[ShipCity], [t7].[ShipRegion], 
  [t7].[ShipPostalCode], [t7].[ShipCountry], [t7].[test], 
  [t7].[CustomerID2], [t7].[CompanyName], [t7].[ContactName], 
  [t7].[ContactTitle], [t7].[Address], [t7].[City], [t7].[Region], 
  [t7].[PostalCode], [t7].[Country], [t7].[Phone], [t7].[Fax], [t7].[test2],
  [t7].[EmployeeID2], [t7].[LastName], [t7].[FirstName], [t7].[Title], 
  [t7].[TitleOfCourtesy], [t7].[BirthDate], [t7].[HireDate], 
  [t7].[Address2], [t7].[City2], [t7].[Region2], [t7].[PostalCode2], 
  [t7].[Country2], [t7].[HomePhone], [t7].[Extension], [t7].[Notes], 
  [t7].[ReportsTo], [t7].[test3], [t7].[ShipperID], [t7].[CompanyName2], 
  [t7].[Phone2]
FROM (
  SELECT ROW_NUMBER() OVER (ORDER BY [t0].[OrderID], [t0].[CustomerID], 
    [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], 
    [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], 
    [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], 
    [t0].[ShipPostalCode], [t0].[ShipCountry], [t2].[test], 
    [t2].[CustomerID], [t2].[CompanyName], [t2].[ContactName], 
    [t2].[ContactTitle], [t2].[Address], [t2].[City], [t2].[Region], 
    [t2].[PostalCode], [t2].[Country], [t2].[Phone], [t2].[Fax], 
    [t4].[test], [t4].[EmployeeID], [t4].[LastName], [t4].[FirstName], 
    [t4].[Title], [t4].[TitleOfCourtesy], [t4].[BirthDate], [t4].[HireDate], 
    [t4].[Address], [t4].[City], [t4].[Region], [t4].[PostalCode], 
    [t4].[Country], [t4].[HomePhone], [t4].[Extension], [t4].[ReportsTo], 
    [t6].[test], [t6].[ShipperID], [t6].[CompanyName], [t6].[Phone]) 
  AS [ROW_NUMBER], 
    [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], 
    [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], 
    [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], 
    [t0].[ShipPostalCode], [t0].[ShipCountry], [t2].[test], 
    [t2].[CustomerID] AS [CustomerID2], [t2].[CompanyName], 
    [t2].[ContactName], [t2].[ContactTitle], [t2].[Address], [t2].[City], 
    [t2].[Region], [t2].[PostalCode], [t2].[Country], [t2].[Phone], 
    [t2].[Fax], [t4].[test] AS [test2], [t4].[EmployeeID] AS [EmployeeID2], 
    [t4].[LastName], [t4].[FirstName], [t4].[Title], [t4].[TitleOfCourtesy], 
    [t4].[BirthDate], [t4].[HireDate], [t4].[Address] AS [Address2], 
    [t4].[City] AS [City2], [t4].[Region] AS [Region2], 
    [t4].[PostalCode] AS [PostalCode2], [t4].[Country] AS [Country2], 
    [t4].[HomePhone], [t4].[Extension], [t4].[Notes], [t4].[ReportsTo], 
    [t6].[test] AS [test3], [t6].[ShipperID], 
    [t6].[CompanyName] AS [CompanyName2], [t6].[Phone] AS [Phone2]
  FROM [dbo].[Orders] AS [t0]
    LEFT OUTER JOIN (
      SELECT 1 AS [test], [t1].[CustomerID], [t1].[CompanyName], 
        [t1].[ContactName], [t1].[ContactTitle], [t1].[Address], 
        [t1].[City], [t1].[Region], [t1].[PostalCode], [t1].[Country], 
        [t1].[Phone], [t1].[Fax]
      FROM [dbo].[Customers] AS [t1]
        ) AS [t2] ON [t2].[CustomerID] = [t0].[CustomerID]
    LEFT OUTER JOIN (
      SELECT 1 AS [test], [t3].[EmployeeID], [t3].[LastName], 
        [t3].[FirstName], [t3].[Title], [t3].[TitleOfCourtesy], 
        [t3].[BirthDate], [t3].[HireDate], [t3].[Address], [t3].[City], 
        [t3].[Region], [t3].[PostalCode], [t3].[Country], [t3].[HomePhone], 
        [t3].[Extension], [t3].[Notes], [t3].[ReportsTo]
      FROM [dbo].[Employees] AS [t3]
        ) AS [t4] ON [t4].[EmployeeID] = [t0].[EmployeeID]
    LEFT OUTER JOIN (
        SELECT 1 AS [test], [t5].[ShipperID], [t5].[CompanyName], 
          [t5].[Phone]
        FROM [dbo].[Shippers] AS [t5]
        ) AS [t6] ON [t6].[ShipperID] = [t0].[ShipVia]
    ) AS [t7]
WHERE [t7].[ROW_NUMBER] > @p0',N'@p0 int',@p0=15


В общем, если шеф такое увидит, я не знаю, что со мной будет. Ясно одно — будет больно и недолго.

Удачи вам в освоении новых технологий)
Re[5]: LINQ to SQL. первые разочарования.
От: IB Австрия http://rsdn.ru
Дата: 11.12.07 10:21
Оценка:
Здравствуйте, снежок, Вы писали:

С>Просто существуют data-ориентированные системы/решение и решения где тяжеловато обойтись без разветвленных бизнес-классов.

Хм. Либо data-ориентированное приложение, либо развесистые бизнес-классы. А так — да, LINQ2SQL предназначен для data driven решений.
Мы уже победили, просто это еще не так заметно...
Re[5]: LINQ to SQL. первые разочарования.
От: vdimas Россия  
Дата: 11.12.07 10:39
Оценка:
Здравствуйте, tripolox, Вы писали:


VD>>Не спеши возмущаться. Твое сознание зашорено теми догмами которые впишивали в него индустриальные проповедники. Возможно когда-то ты прицдешь к выводу, что O/R-маперы шаг в не верном направлении.


T>Где же верное направление?


Уметь вернуться к структурам, т.е. к кортежам, когда речь идёт о данных. Классический объект — это сущность, которая прячет своё устройство, а данные наоборот — на виду. Где-то должен быть плавный и безболезненный переход из одной абстракции в другую.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[4]: LINQ to SQL. первые разочарования.
От: снежок Россия  
Дата: 11.12.07 15:03
Оценка: +1
Тут даже сложно еще что-либо добавить...
Я тоже не сторонник "авто-запросов", поэтому если и интересовался какими-либо ORM-ами и Mapping-Helper-ами, всегда в первую очередь смотрел на возможность пустить их CRUD-логику через использование хп, а на прямые обращения к таблицам и вьюхам вообще права отбираю всегда.
Но до сих пор более менее нормального не существовало и наверное не существует.
Я пытаюсь рассмотреть EDF не с точки зрения "авто-генератора запросов налету", а скорее как Bussiness Object Library + Mapping-Helper на storedProc (это тоже не совсем тривиальная задача), если это будет нормально получаться, то почему бы и нет?
Но я, так же как и ты, никогда не буду работать с сервером посредством вот такой вот тупой авто-генерации запросов, будь то EDF,LINQ или NHibernate или еще что-либо.
В случае необходимости разобраться с косяками, запускаешь профайлер и можно сразу идти за веревкой с мылом, потому как разобраться в таком бардаке...
Re[5]: LINQ to SQL. первые разочарования.
От: VladD2 Российская Империя www.nemerle.org
Дата: 11.12.07 15:18
Оценка: +3
Здравствуйте, tripolox, Вы писали:

VD>>Не спеши возмущаться. Твое сознание зашорено теми догмами которые впишивали в него индустриальные проповедники. Возможно когда-то ты прицдешь к выводу, что O/R-маперы шаг в не верном направлении.


T>Где же верное направление?


На мой взгляд O/R-маперы шаг в никуда. Данные == списки. LINQ to SQL средство повзволяющиее обрабатывать списки данных с приемлемым качеством и без существенных компромисов.
Большинство же O/R-маперов предполагают, что данные == отражение объектов на хранилище данных (persistent storage). Идея "постоянного хранения объектов", на мой взгляд является полной глупостью. Объектв — это представление данных в програме. Они не должны существовать виртуально. Мы создаем их чтобы облегчить свое восприятие данных.

Линк позволяет оперировать непосредсвенно кортежами. Достаточно создать простой слой абстракции между кортежами и представлением данных для клиента и все эти заморочки с O/R-маперами можно забыть как недоразумение.

На самом деле SQL и его эмуляция в LINQ намного мощьнее нежели стандартные методы предлагаемые императивным программированием (по существу тупые переборы). Достаточно сравнить:
foreach (cust in customers)
{
    Orders ords = Lookup(orders, cust.id);
    if (ords.Amount >= 100 && cust.Discount > 0)
        WriteLine("Пользователь {0} имеет скидку {1} в заказе {1}", 
            cust.Name, ords.Amount, ords.id);
}

и
vr result = cust in customers, ords in orders 
    where ord.customer_id == cust.customer_id && ords.Amount >= 100 && cust.Discount > 0;
foreach (x in from result)
    WriteLine("Пользователь {0} имеет скидку {1} в заказе {1}", 
            x.Name, x.Amount, x.id)

Второй вариант более декларативен. Его можно и исполнить более эффективно (передать SQL-серверу который оптимизирует его выполнение), и читать проще (мы точно не встретим импиративных изменений получаемой коллекции или побочных действий).

Конечно над O/R-маперами тоже можно наворотить движок запросов. Вот только зачем сначала превращать списки в сложные иерархии объектов, а затем обратно? Это ведь приведет к неоптимальности и подвигнет работать с данными тем самым тупым перебором (как в первом примере). А это убьемт декларативность и создаст сложнсоти (ведь в императивном коде могут быть любые невидимые зависимости).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: LINQ to SQL. первые разочарования.
От: VladD2 Российская Империя www.nemerle.org
Дата: 11.12.07 15:18
Оценка: 8 (3) +2
Здравствуйте, снежок, Вы писали:

С>Скорее тут не направление может оказаться неправильным, а применение.

С>Просто существуют data-ориентированные системы/решение и решения где тяжеловато обойтись без разветвленных бизнес-классов. Вот, видимо, LINQ to SQL позиционируется как решение для data-ориентированных систем. И хотя EDF полностью покрывает по возможностям LINQ to SQL — это весьма далекие друг от друга продукты.

Мнея очень давно интересовал странный факт. Много кто пытался создать O/R-маперы, но ни у кого так и не удалось создать "идеальный O/R-мапер". Все что получалось проигрывало по скрости и удобству SQL-ю который был придуман IBM чуть ли не раньше чем появился термин ООП. В итоге я прише к парадоксальному виводу. ОО-языки програмиирования более низкоуровневы нежели SQL. SQL — это декларативный язык запросов к абстрактным данным. ООП же подразумевает императивную обработку данных, которая являеся черезчур низкоуровневой. ООП с одной стороны привносит абстрации вроде инкапсуляции, полиморфизма и наследования, но с другой ничего не предлагает в области конструирования и выполнения запросов к данным. А БД — это в первую очередь хранилища данных. Причем списков данных, если быть более точным. В итоге O/R-мапер преуспели в области упаковки данные в объекты, но ровным счетом ничего не смогли предложить в области получения и обработки данных. Лучшее что было в них изобретено — это текстовые запросы которые в итоге конвертируются в запросы к БД.

Дикая идея "пирсистентности" по которой объекты живут дольше своей реальной жизни привели к проблемам опережающего чтения (надо ли при считывании заказа читать данные покупателя по этому заказу?) и т.п.
Линк — это попытка по рдугому взглянуть на данные. Не объекто ориентированно (в то же время представляя данные в виде объектов по мере возможности).
Мы просто аппелируем к спискам данных. Причем не важно в каком виде. Мы просто строим запросы к ним и получаем списки данных. Мы просим дать нам информацию из заказа, покупателя и еще чего-то и получаем только то что нужно. Проблема опережающего чтения отпадает сама собой, так как мы сами указываем то что хотим получить. Так же пропадает проблема императивности. Мы вместо горы if-ов и for/foreach-ев получаем стройный запрос который формулируется в терминах всего 4-5 фукнциональных примитивов (from, wheere, order by, select и т.п.).

В общем, объекты в Линке не более чем средство описать данные для того чтобы удобнее оперировать ими во время исполнения, а не идея спрецировать объектную модель на БД. И это замечательно, так как SQL-СУБД более гибка в области обработки данных нежели тот ООП котрый навязывается массам "умными книжками".

Причем ООП никто не отменяет. Все его приемущества можно использовать на уровне приложения. А при зарпросе к данным ползоваться терминами и абстракциями БД.

С>p/s/ спасибо за участие


Не за что. Я выражаю свое мнение которое может быть не верным.
Просто я в последнее время немало времени посвятил так называемому фунциональному стилю программирования, где упор делается не на объекты в понимании ООП, а на списки более открытых структур данных, и понял, что в этом что-то есть.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: LINQ to SQL. первые разочарования.
От: VladD2 Российская Империя www.nemerle.org
Дата: 11.12.07 15:41
Оценка: 1 (1) -1 :)
Здравствуйте, Sinix, Вы писали:

S>Ну и мои 5 копеек. Сразу, чтоб не флеймить. Сам по себе LINQ — забавная идея. Но вот реализация...


S>Она дико сырая.


Идея старше тебя и очень продумана. Ты наврено даже не подозреваешь, что базис этой идеи нзывается "Лямбда исчисления Чёрча".

S> Безумно раздражает, что вместо того, чтобы работать с сиквелом, который я знаю и понимаю, я должен работать с какой-то финтифлюшкой, которая изображает из себя сиквел, как его видят разработчики финтифлюшки.


Проблема в том, что создатели "финтифлюшки" считают тебя и дугих C#-разработчиков быдлокодерами которым бессмысленно давать суровую мат.модель лежащую под их решением. Они считают, что большинство C#-разработчиков — это индусы (по призванию, а не по национальности), и они тупо не поймут мудренного обоснования. Меж тем основание у Линк-а очень серьезное. SQL — это только форма.

S> Плохо видят кстати. Меня задолбало пытаться написать LINQ-запрос так, чтоб он хотя бы примерно соответствовал тому, что должно быть и угадывать, как поведёт себя SelectMany в сочетании с GroupBy и GroupJoin (да, кстати, Left Join'a нет. Потомучта.).


Это проблема абстрагирования. Запрос в Линк — это абстракция которая преобразуется в SQL в случае LINQ to SQL. Понятно, что "не идеальные оптимизаторы" БД могут воспринять получающийся запрос не очень адекватно. Но над СУБД и их оптимизаторами будут работать, и рано или поздно даже самые не оптимальные запросы будут выполняться оптимально, и эта проблема уйдет сама собой. А пока что мы вльны химичит с вьюхами и другими косвенными структурами СУБД, чтобы заставить СУБД воспринимать "линкованные" запросы.

S> Задолбало разбираться, почему я должен править что-то в xml-х кишках этого чудо-монстра, чтобы наконец заработали хранимые процедуры, а потом материться и переписывать параметризованные функции на вьюхи, чтобды эта падла нормально загружала details'ы.


Большинство действительно новых решений не совершенно. Можешь потрахаться пару лет с O/R-маперами пока Линк не доведут до ума. Вот только по мне так это убитое время.

S>Ндя. Обещал же. 5 копеек про LINQ for SQL.


S>1. Отсутствие отсоединённого режима работы.

S>Я до сих пор не могу понять, почему либо я использую SqlQuery<T> (или как его там...) и терплю непрекращаюшиеся обращения к серверу на каждый чих,
S> либо пытаюсь использовать EaferLoad с копированием загруженных элементов типа .ToBindingList() и натыкаюсь на весёлые грабли... Потому что EagerLoad тоже через попу работает))) Самое большее, что с его помощью можно добиться — чтобы загружались дети при обращении к родителю. В результате, если у вас 15 родительских записей, вам потребуется обратиться к серверу всего 15 раз. Мило, да?)

Мило. Именно по этому лучше вобще не заморачиваться на идею O/R-мапинга, а делать реальные запросы к реальным данным.

S>2. Производительность. На эту тему даже рыдать не хочется. Я не могу понять, почему жалкие полтыщи master/details строк должны загружаться по три-пять секунд? Аналогичный штук с датаадаптером на порядок шустрее.


Ну, а 0.5-1 секунда — это нормально? А если клиентов 1000, то ждем 16 сек. на запрос (1 000 / 60)?
Не надо тянуть ненужные данные. Это ответ на все вопросы.
Проблема у вас в головах. Вы привыкли к ООП. А данные — это данные. Берите нужные вам 20 строк и не ентитите себе и окружающим мозги разными master/details-ами.
Нужны данные по заказу вместе с деталировкой? Ну, так напиши запрос соеденяющий заказ и его деталировку. Нужен список заказов? Так тяни только его. А уж детали по отдельным заказам вытянишь потом отдельным запросом.

S>3. Lazy load. Ну вот раздражает меня тот факт, что результатом любого запроса могут быть устаревшие данные (не забываем, что все сущности весьма весело кэшируются внутри контекста). Даже если мне надо будет показывать лишь часть данных, я предпочту постраничную выборку. Потому что буду уверен, что все данные согласованы. И не буду гадать, сколько времени назад и что загрузилось.


Разражают? На то есть уровни изоляции. Хотя разумнее не раздражаться, а расчитывать на это. Программы будут более мастабируемыми.

S>4. Невозможность сериализации данных. Точнее так. Сериализовать их можно. А вот восстановить и определить какие данные надо вставить в БД, а какие не изменялись — хрен те. Официальный совет: восстанавливайте оригинальные версии и вносите все изменения заново. Опупеть, да?


Ага. Если думашь шаблонами O/R-маперов. И нормально если думашь о списках данных как о... э... списках данных.

S>5. Убогий сгенеренный код. Если начальство увидит, что код в продакшне обращается к серверу вот так (это для одного (!) родителя):...


А на что оптимизатор у СУБД?

S>В общем, если шеф такое увидит, я не знаю, что со мной будет. Ясно одно — будет больно и недолго.


Если шев дурак, то будет больно. Если умный, то он поймет и осознает тот факт, что неоптимальность запросов соптимизирует умный сервер, а вот выигрышь в контроле типов и интелесенсе будет напрямую увеличивать качество и скорость разработки прикладного кода. В итоге дурка заставит писать код самостоятельно. Умные воспользуется приемуществами ЛИНК-а.

S>Удачи вам в освоении новых технологий)


Во. Во. И пока ее как следует не освоят не стоит выражать сильных негодований. Иначе потом стыдно удет. Ведь болшинство негодований вызвано не реальными недостатками, а банальными штампами мышления навязанными испоьзуемыми до этого технологиями.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: LINQ to SQL. первые разочарования.
От: stump http://stump-workshop.blogspot.com/
Дата: 11.12.07 19:39
Оценка: :)
Здравствуйте, Sinix, Вы писали:

S>Ну и мои 5 копеек. Сразу, чтоб не флеймить. Сам по себе LINQ — забавная идея. Но вот реализация...


S>Она дико сырая. Безумно раздражает, что вместо того, чтобы работать с сиквелом, который я знаю и понимаю, я должен работать с какой-то финтифлюшкой,

... которую ты не знаешь и не понимаешь.
В принципе, дальше можно и не читать. От непонимания сплошные недоразумения. Утихший было холивар SQL vs OOP похоже разгорается вновь.
Давно уже пора понять, что RDBMS и OOP это ортогональные вещи, которые не мешают а прекрасно дополняют друг друга.
Когда в руках из инструментов, один молоток, то все задачи становятся похожими на гвозди (с) не помню. Но стоит взять в руки отвертку, и приходит понимание того, что кроме гвоздей существуют шурупы. И шурупы по сравнению с гвоздями имеют просто уникальные, казавшиеся раньше невозможными, свойства. Например, их легко можно выкрутить (если конечно, они не были забиты молотком ).
Увидел дизайнер в новой студии, ух ты — таблички мапятся на классы, значит новый ORM. А как сюда свои родные хранимки прикрутить? Не прикручиваются? Полный отстой! Гвозди забивать не удобно, а так похоже на молоток...

LINQ это интегрированый в язык механизм запросов для работы с наборами данных. А LINQ2SQL это всго лишь один из интерфейсов для этого механизма (наряду с LINQ2Entity, LINQ2XML, LINQ over dataset etc.)
LINQ вовсе не "изображает из себя сиквел", семантика похожая, но больше ничего общего. По идеалогии LINQ гораздо ближе к XSLT чем к SQL.

S>В общем жопа всё это. Впрочем, не меньшая, чем EF. Последнее вообще, по-моему, бред полный, ибо трактуется как средство для выноса концептуальной модели на сторону клиента.


Это где же ты такого наслушался? EF предлагает отделить концептуальную модель данных от физической. И для этого у него есть довольно развитый механизм маппинга. Это, кстати, помогает решить проблему, о которой ты говоришь далее:
S>А теперь учтите, что у нас не одно приложение базу юзает. И каждое должно видеть эту базу по-своему, и не лезть куда не положено... У каждого приложения должна быть своя концептуальная модель, да?)))

Твоя база — это физическая модель, а каждое приложение как раз может иметь свою концептуальную модель, которые мапятся на одну физическую.
S>В общем от лукавого всё это...
В общем, поменьше надо сосредотачиваться на том, что, куда и как проинсталирует тебе начальник, а побольше на сути изучаемых технологий.
Тогда бы стало очевидно, что за отложенной загрузкой, отсоединенным режимом работы с данными, сериализацией и прочими вещами надо идти в Entity Framework а не кувыркаться с Linq2Sql. Выгружать тысячи записей master/details было модно и нужно в давние времена клиент серверных архитектур (которые по этим причинам и почили в бозе), а для масштабируемых приложений так делать не принято. и т.д и т.п.

S>5. Убогий сгенеренный код. Если начальство увидит, что код в продакшне обращается к серверу вот так (это для одного (!) родителя):


А чем конкретно код не понравился?
Недавно, кстати прочитал где то в блогах что в команду EF специально откомандировали лучших спецов по оптимизации запросов из SQL Server core team.
Понедельник начинается в субботу
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.