Linq extension method error

A

Andrus

Jon, I checked MSDN doc:
I don't believe a LINQ to
SQL context will close its connection automatically without calling
Dispose on it - at least not in a timely manner.

MSDN doc:
A DataContext opens and closes a database connection as needed if you
provide a closed connection or a connection string.

So LINQ to SQL closes passed connection object *without* dispose to be able
to re-open it later.
it's good practice to dispose of an object which implements
IDisposable when you know you've finished with it.

MSDN doc: In general, you should never have to call Dispose on a
DataContext.

So MSDN doc considers *bad* practice to dispose DataContext object.

I tried to use your recommendations and Marc sample to dispose immediately
and created code

IQueryable<T> Queryable;

using ( var db = nortwind(CONNSTRING) ) {
Queryable = from b in db.Customers() select b;

}

in paged grid data retrieval method (executed if user presses page down in
virtual grid) I used

IList<T> SupplyPageOfData(int lowerPageBoundary, int rowsPerPage) {
return Queryable.Skip(lowerPageBoundary).Take(rowsPerPage).ToList();
}


line

Queryable.Skip(lowerPageBoundary).Take(rowsPerPage).ToList();

causes exception:

Connection is not open

How to fix ?

Andrus.
 
J

Jon Skeet [C# MVP]

Andrus said:
MSDN doc:
A DataContext opens and closes a database connection as needed if you
provide a closed connection or a connection string.

So LINQ to SQL closes passed connection object *without* dispose to be able
to re-open it later.

Again, if you don't provide a connection to start with.
MSDN doc: In general, you should never have to call Dispose on a
DataContext.

So MSDN doc considers *bad* practice to dispose DataContext object.

Since when does "in general you should never have to do X" equate to
"it's bad practice to do X"?
I tried to use your recommendations and Marc sample to dispose immediately
and created code

IQueryable<T> Queryable;

using ( var db = nortwind(CONNSTRING) ) {
Queryable = from b in db.Customers() select b;

}

in paged grid data retrieval method (executed if user presses page down in
virtual grid) I used

IList<T> SupplyPageOfData(int lowerPageBoundary, int rowsPerPage) {
return Queryable.Skip(lowerPageBoundary).Take(rowsPerPage).ToList();
}

line

Queryable.Skip(lowerPageBoundary).Take(rowsPerPage).ToList();

causes exception:

Connection is not open

How to fix ?

Hmm. This seems to be a case of IDisposable being inappropriate.
Perhaps you really should rid of the "using" statement after all. I'd
still put it in where possible, on general principle, but this does
seem to be an odd case.

I still maintain that avoiding calling it to avoid the miniscule
performance hit is a bad reason though.

I'll see if I can get in touch with the LINQ to SQL team to find out
why it implements IDisposable at all.
 
A

Andrus

I'll see if I can get in touch with the LINQ to SQL team to find out
why it implements IDisposable at all.

I VCSE 2008 is not capable to step into DataContext Dispose method source
and I do'nt have Reflector installed so I cannot check it.
Maybe somebody can in VS step into.
First I throught that DataContext opens and does not close connection when
in transaction but this seems to be not so, it uses existing connection.

Andrus.
 
A

Andrus

Hmm. This seems to be a case of IDisposable being inappropriate.
Perhaps you really should rid of the "using" statement after all. I'd
still put it in where possible, on general principle, but this does
seem to be an odd case.

I expect that it is good practice to build dynamic linq query once and use
it later many times in temporary db contexts.

I changed my code to

IQueryable<T> Queryable;

void BuildQuery() {
var db = nortwind();
Queryable = from b in db.Customers select b;
}

in data retrieve method I need to use

IList<Customer> SupplyPageOfData(int lowerPageBoundary, int rowsPerPage) {
return Queryable.Skip(lowerPageBoundary).Take(rowsPerPage).ToList();
}

What happens when .NET runtime disposes db object ?

Will this cause random and difficult to track errors like "object is being
used after being disposed" ?

Is this best way to implement paged queries in GUI application where data
lives long time?

Or should I move code from BuildQuery to SupplyPageOfData and build query
expression for every paged data access ?

Andrus.
 
A

Andrus

In addition, if future providers (implementations of IProvider) hold
other resources, it's reasonable to assume that disposing the
DataContext will clear them up. It's just good practice to dispose of
things implementing IDisposable.

I peroformed full-text search of local MSDN for "IProvider"
Search does not return any results.
So I do'nt understand what is IProvider
There is no any information which is required for provider implementation.
Nobody knows classes, methods, properties and events which Linq provider
must implement to consided to be complete.
Your argument about wasting CPU time doesn't hold water - can you even
*measure* the amount of time which is "wasted"?

For application which makes hundreds of queries per second additional time
required to dispose is be significant.
..NET framework addresses this issue by perfoming lazy dispose. No need to
force it in application without need.
Compare that amount of
time with the time it takes to establish a connection to the database
in the first place, and you'll see how completely insignificant it is.

Connection is taken from ADO .NET provider connection pool.
For rapid queries, connection is keep opened in pool. So this amount of time
is insignificant. This delay cannot be avoided by application design.
DataContext dispose time can be avoided. This is difference.

I'm thinking about using DataContext as long-time cache provider for GUI
application.
Global read-only DataContext can be used as as cache. All queries which
should be cached must be exectued against this global context. I have many
queries which returns object by id. Those queries can be satisfied from this
simple cache easily without database hit.
All data modifications which can destroy context are performed in temporary
data contexts created for unit of work.
Is this reasonable ?

Other way should be to implement entity caching by creating new data access
layer ("entity persistence manager") which caches data and makes accesses
using Linq.
However this caching in linq application unnessacarily complicated.

Andrus.
 
J

Jon Skeet [C# MVP]

Andrus said:
I expect that it is good practice to build dynamic linq query once and use
it later many times in temporary db contexts.

In that situation you should you CompiledQuery.Compile.

What happens when .NET runtime disposes db object ?

The runtime doesn't dispose of anything - the runtime doesn't know
about IDisposable. What happens in each individual class is up to that
class.
Will this cause random and difficult to track errors like "object is being
used after being disposed" ?

Is this best way to implement paged queries in GUI application where data
lives long time?

You need to work out how to implement paging (with various options
being available), but you certainly shouldn't do it by keeping an open
connection all the time. I wouldn't keep an open context either, even
if it *doesn't* keep the connection open.
Or should I move code from BuildQuery to SupplyPageOfData and build query
expression for every paged data access ?

Either that or use a compiled query.
 
J

Jon Skeet [C# MVP]

Andrus said:
I peroformed full-text search of local MSDN for "IProvider"
Search does not return any results.
So I do'nt understand what is IProvider
There is no any information which is required for provider implementation.
Nobody knows classes, methods, properties and events which Linq provider
must implement to consided to be complete.

Microsoft does - that's the important thing. IProvider is a provider
interface internal to LINQ to SQL. There's only one implementation at
the moment, I believe, but that could change.
For application which makes hundreds of queries per second additional time
required to dispose is be significant.

Have you measured it? I doubt you'll find you can even tell the
difference. Don't micro-optimise without evidence. In every case where
you're talking to a database - even using IPC - the database query will
dwarf the cost of calling Dispose.
.NET framework addresses this issue by perfoming lazy dispose. No need to
force it in application without need.

Relying on a finalizer is generally a really bad idea. It may not
matter in this case (and I would guess DataContext doesn't even have a
finalizer, although I haven't checked) but it should be avoided.
Connection is taken from ADO .NET provider connection pool.
For rapid queries, connection is keep opened in pool. So this amount of time
is insignificant. This delay cannot be avoided by application design.
DataContext dispose time can be avoided. This is difference.

No, the time taken by Dispose is the insignificant time - try measuring
it.
I'm thinking about using DataContext as long-time cache provider for GUI
application.
Global read-only DataContext can be used as as cache. All queries which
should be cached must be exectued against this global context. I have many
queries which returns object by id. Those queries can be satisfied from this
simple cache easily without database hit.
All data modifications which can destroy context are performed in temporary
data contexts created for unit of work.
Is this reasonable ?

I don't personally think you're using LINQ to SQL in the way it was
intended. To be honest, I doubt many people are using it for 2-tier
applications.

Is your user the only one who will be using the application at any one
time? If not, you've got the signficant risk of all the data being out
of date anyway.
 
M

Marc Gravell

.NET framework addresses this issue by perfoming lazy dispose

No, it really doesn't; .NET provides garbage collection (GC), but that
is something completely separate. In fact, in a high volume system you
absolutely *want* to be disposing ASAP - as this will allow any pooled
objects to return to the pool for immediate re-use, minimising the
size of the pool. It can also help to flatten the workload profile by
spreading all the dispose work uniformly, rather than a sudden big
lump when GC collects; obviously GC still has to reclaim the actual
RAM (hopefully from GEN0 at negligible cost), but it generally doesn't
have to bother finalizing things that have already been disposed
(GC.SuppressFinalize is common practice in Dispose() for an object
that is both IDisposable and has a finalizer).

Marc
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,



line

Queryable.Skip(lowerPageBoundary).Take(rowsPerPage).ToList();

causes exception:

Connection is not open

Remember that the data is not retrieved until the first use. That's why your
code throw an exception. I think this is why MSDN recommend to not dispose
it.

IMHO you should either use a connection string as the parameter to the
DataContext, this would allow the DataContext to create and handle its
connection.
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,


I do not think that the source code for the Linq library was made public.

I believe they implemented IDisposable cause they use types that do
implement it (like Connection). You can (even should) use the pattern as
long as you know how it's used:

using ( var db = nortwind(CONNSTRING) ) {
Queryable = from b in db.Customers() select b;

}

In the above context you have not ended using the DataContext. The data
context is still needed for when the query is actually performed.
So basically you are disposing an instance that is needed later on.
 
A

Andrus

I believe they implemented IDisposable cause they use types that do
implement it (like Connection). You can (even should) use the pattern as
long as you know how it's used:

using ( var db = nortwind(CONNSTRING) ) {
Queryable = from b in db.Customers() select b;

}

Ignacio,

As far as I know this pattern is not capable to provide scope over windows
message loop and several methods invoked in Windows form.

In GUI virtual grid, Queryable variable is typically built once when form is
created. It is used for paged data retrieval later, maybe after 10-30
minutes, when user presses page down key in grid.


If I understand properly, you recommend not to dispose DataContext for whole
datagrid live time ?
Is this best way ?
Jon recommends to compile query. Does compiling query allow to use this
design pattern ?

Which is best DLinq design patter for GUI application of this kind ?

Andrus.
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

If I understand properly, you recommend not to dispose DataContext for
whole
datagrid live time ?

Yes, that is my recommendation, and frankly I think is the only way it will
work. Create the context when you first need it, and dispose it when you do
not need it anymore, most probably that is create it in the Load event and
dispose it in the Closing event.
Is this best way ?
Jon recommends to compile query. Does compiling query allow to use this
design pattern ?

Not sure, IMO it's not the problem if compiling the query but running it.
IIRC the docs says that linq 2 sql is lazy, it does execute the query when
the query is used.
 
A

Andrus

You need to work out how to implement paging (with various options
being available), but you certainly shouldn't do it by keeping an open
connection all the time. I wouldn't keep an open context either, even
if it *doesn't* keep the connection open.


Either that or use a compiled query.

Jon,

I do'nt understand "use a compiled query"

Using your recommendation I need to execute query after DataContext object
which created it is disposed.
Query is tightly coupled to DataContext which creates it.

How query created in one DataContext can be run in other DataContext ?

Andrus.
 
J

Jon Skeet [C# MVP]

I do'nt understand "use a compiled query"

Using your recommendation I need to execute query after DataContext object
which created it is disposed.

No, that's not what I was saying at all.
Query is tightly coupled to DataContext which creates it.

How query created in one DataContext can be run in other DataContext ?

Compiling a query doesn't create one in one DataContext - it creates
something which can be given a *new* DataContext. Look at the docs and
search on the web and you'll see what I mean.
 
J

Jon Skeet [C# MVP]

MSDN doc: In general, you should never have to call Dispose on a
DataContext.

<snip>

I mailed Matt Warren about this, asking where DataContext implements
IDisposable, and his reasons are below. I'm not sure to what extent I
agree with them, so don't necessarily expect to defend them, but it's
still nice to know what they are :)

<quote>
1) If application logic needs to hold onto an entity beyond when the
DataContext is expected to be used or valid you can enforce that
contract by calling Dispose. Deferred loaders in that entity will still
be referencing the DataContext and will try to use it if any code
attempts to navigate the deferred properties. These attempts will fail.
Dispose also forces the DataContext to dump its cache of materialized
entities so that a single cached entity will not accidentally keep
alive all entities materialized through that DataContext, which would
otherwise cause what appears to be a memory leak.

2) The logic that automatically closes the DataContext connection can
be tricked into leaving the connection open. The DataContext relies on
the application code enumerating all results of a query since getting
to the end of a resultset triggers the connection to close. If the
application uses IEnumerable's MoveNext method instead of a foreach
statement in C# or VB, you can exit the enumeration prematurely. If
your application experiences problems with connections not closing and
you suspect the automatic closing behavior is not working you can use
the Dispose pattern as a work around.
</quote>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top