Complex object in the form of a grid.

I have a gridview whose data source is the following function:

public static List<Train> GetTrainsByIDs(int [] ids) { using (var context = new MyEntities()) { return ids.Select(x => context.Trains.Single(y => y.TrainID ==x)).AsQueryable().Include(x=>x.Station).ToList(); } } 

The grid has an ItemTemplate <%# Eval("Station.Name") %> . This causes the error. The ObjectContext instance has been disposed and can no longer be used for operations that require a connection , despite the fact that I used the include method.

When I change the function to

 public static List<Train> GetTrainsByIDs(int [] ids) { using (var context = new MyEntities()) { return context.Trains.Where(x => ids.Contains(x.TrainID)).Include(x=>x.Station).ToList(); } } 

it works fine, but then they exit in the wrong order, and also if I have 2 identifiers, then I would like to have two identical trains on the list.

Is there anything I can do besides creating a new viewmodel? Thanks for any help

+4
source share
2 answers

After reading the @Gert Arnold answer and getting the idea to do it in 2 steps, I was able to very easily use the first request like this:

 using (context = new MyEntities()) { var trns = context.Trains.Include(x => x.Station); return ids.Select(x => trns.Single(y => y.TrainID == x)).ToList(); } 
0
source

Regarding the first request: this is a deferred execution. You created IEnumerable from Train s, noticed that it does not have an Include method, so add it to IQueryable , add Include and add ToList() to prevent lazy loading.

But according to MSDN in DbExtensions.Include :

This extension method calls the Include (String) method of the original IQueryable, if one exists. If the source IQueryable does not have a matching method, then this method does nothing.

(my emphasis)

The result of the selection is IEnumerable , converted to IQueryable , but now implemented by EnumerableQuery , which does not implement Include . And nothing happens.

Now the data gets into the grid, which tries to display the station, which starts lazy loading when the context is gone.

In addition, this project has another drawback: it runs a query for each identifier separately.

So the second query is much better. This is one request including Station s. But now the order is dictated by the order that the database wants to return. You can use Concat to solve this problem:

 IQueryable<Train> qbase = context.Trains.Include(x=>x.Station); IQueryable<Train> q = null; foreach (var id in ids) { var id1 = id; // Prevent modified closure. if (q == null) q = qbase.Where(t => t.Id == id1); else q = q.Concat(qbase.Where (t => t.Id == id1)); } 

The generated request is not very elegant (at least), but in the end it is one request, not many.

+1
source

All Articles