5

The following is the C# code and generated SQL in a LINQ to SQL query for two cases.

Case 1

using (JulianDataContext dc = new JulianDataContext(this.CurrentConnectionString))
{
#if DEBUG
    dc.Log = new DebugTextWriter();
#endif

    IEnumerable<UserNewsfeedDeliveryTime> temp = dc.UserNewsfeedDeliveryTimes.Where(u => u.NewsfeedEmailPeriodicity > 0 && DateTime.Today >= u.NextNewsfeedDelivery.Value.Date);

    ids = temp.Select(p => p.Id).ToList();
}

SELECT [t0].[Id], [t0].[NewsfeedEmailPeriodicity], [t0].[LastSentNewsfeedEmail], [t0].[NextNewsfeedDelivery]
FROM [dbo].[UserNewsfeedDeliveryTimes] AS [t0]
WHERE ([t0].[NewsfeedEmailPeriodicity] > @p0) AND (@p1 >= CONVERT(DATE, [t0].[NextNewsfeedDelivery]))
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [0]
-- @p1: Input DateTime (Size = -1; Prec = 0; Scale = 0) [15-11-2012 00:00:00]

Case 2

using (JulianDataContext dc = new JulianDataContext(this.CurrentConnectionString))
{
#if DEBUG
            dc.Log = new DebugTextWriter();
#endif
    IEnumerable<UserNewsfeedDeliveryTime> temp = dc.GetTable<UserNewsfeedDeliveryTime>();

    temp = temp.Where(u => u.NewsfeedEmailPeriodicity > 0 && DateTime.Today >= u.NextNewsfeedDelivery.Value.Date);

    ids = temp.Select(p => p.Id).ToList();
}
SELECT [t0].[Id], [t0].[NewsfeedEmailPeriodicity], [t0].[LastSentNewsfeedEmail], [t0].[NextNewsfeedDelivery]
FROM [dbo].[UserNewsfeedDeliveryTimes] AS [t0]

The difference

The difference between these two linq queries:

dc.UserNewsfeedDeliveryTimes

and

dc.GetTable<UserNewsfeedDeliveryTime>()

Why? Could it be that, in case 2, LINQ to SQL is retrieving all data from database and finish the query by filtering all objects in memory?

If so, how can we make keep this generic and still force all the T-SQL to be generated?

Solution

Both answers, are correct but I had to pick one, sorry! I think also it is interesting to add that in this case, since I changed to work with an IQueryable (inherits from IEnumerable), in this line:

temp = temp.Where(u => u.NewsfeedEmailPeriodicity > 0 && DateTime.Today >= u.NextNewsfeedDelivery.Value.Date);

I had two overload methods, one from the IQueryable interface and another to the IEnumerable interface.

public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

So I had to convert my predicate explicitly to Expression> predicate, otherwise the IEnumerable interface method would have been picked up at compile time and, if I am not mistaken, I would get some dynamic sql exception saying the T-SQL could not have been generated.

4

2 回答 2

2

Try using IQueryable instead of IEnumerable.

Weird, because on my examples I get the opposite results from you, ie with IEnumerable, case 1 works fast and case 2 retrieves all the data. But using IQueryable fixes the issue.

于 2012-11-16T11:18:55.393 回答
2

From my understanding, IEnumerable does not transform the original query information that IQueryable holds. It's almost as if the cast freezes any changes to the IQueryable query at the point of casting. If you look at MSDN, it turns out that IQueryable inherits IEnumerable:

http://msdn.microsoft.com/en-us/library/system.linq.iqueryable.aspx

Hence, you see this behaviour. It is important with LINQ-SQL to work with IQueryable unless you want the query frozen at the point it is turned to an IEnumerable.

In your first example, the where is inclusive of the original query. The select is not hence the query generated.

In your second example, you capture the table itself into an IEnumerable. Any changes on top of this are done in memory on top of the original query.

When you think, the IEnumerable version of where will not be able to transform the original data of the IQueryable due to the cast and how inheritance works.

When you also consider deferred loading, and how LINQ works, this seems to make sense. To me it is a big annoyance, as it can lead you into generating some terrible performing code.

于 2012-11-16T18:48:40.200 回答