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


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

Удачи вам в освоении новых технологий)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.