LINQ style and performance in ProjectTracker Lists

LINQ style and performance in ProjectTracker Lists

Old forum URL: forums.lhotka.net/forums/t/4582.aspx


phm posted on Saturday, March 29, 2008

Although strictly speaking this is not a bug, IMHO the way the ProjectTrackers example fills the lists using LINQ is not optimal.

For example, in RoleList.DataPortal_Fetch() adding

         ctx.DataContext.Log = Console.Out;

at the beginning of the method shows (in the output window of the debugger) that the generated query is:

SELECT [t0].[Id], [t0].[Name], [t0].[LastChanged]
FROM [dbo].[Roles] AS [t0]

This gets all columns from the database, including the unused LastChanged. Not a big deal in this particular situation, but could be worse for a table with many columns.

Moving the new NameValuePair(role.Id, role.Name) into the query expression instead of the foreach loop:

        var data = from r in ctx.DataContext.Roles
                   select new NameValuePair(r.Id, r.Name);
        IsReadOnly = false;
        foreach (var role in data)
            this.Add(role);
        IsReadOnly = true;

allows LINQ to only query the needed columns:

SELECT [t0].[Id] AS [key], [t0].[Name] AS [value]
FROM [dbo].[Roles] AS [t0]

Adding an AddRange(IEnumerable<T>) to ExtendedBindingList<T> would then allow to write

            this.AddRange(data);

instead of the loop, or even

            this.AddRange(from r in ctx.DataContext.Roles
                   select new NameValuePair(r.Id, r.Name));

In more complex situations, where the query is created in several steps (such as in ProjectList), the select new ... has to be done at the very end, by adding a last step to the query construction. You can for example substitute this for the foreach loop:

        this.AddRange(from p in data
                      select new ProjectInfo(p.Id, p.Name));

The original query (with optional filter)

SELECT [t0].[Id], [t0].[Name], [t0].[Started], [t0].[Ended], [t0].[Description], [t0].[LastChanged]
FROM [dbo].[Projects] AS [t0]
WHERE [t0].[Name] LIKE @p0
-- @p0: Input VarChar (Size = 10; Prec = 0; Scale = 0) [%Business%]

then becomes

SELECT [t0].[Id] AS [id], [t0].[Name] AS [name]
FROM [dbo].[Projects] AS [t0]
WHERE [t0].[Name] LIKE @p0
-- @p0: Input VarChar (Size = 10; Prec = 0; Scale = 0) [%Business%]

RockfordLhotka replied on Sunday, March 30, 2008

Good suggestions, thanks! I'll put an AddRange() method into CSLA.

Copyright (c) Marimer LLC