Databinding multiple controls to a single LINQ query - c#

I have a LINQ query I wish to run and drop the result into a var or IQueryable. However, I'm binding the result to multiple (4 to 10) controls and only want the query to run once.
When I just put the result into all the datasource values, the query runs for every control and the controls (comboboxes, for example), change selectedvalues to match each other whenever any of them is changed.
When I databind the controls to the result.ToList() or something similar, that fixes the synchronization problem (i.e. they behave independently as they should), but the query still runs once for every control.
This was easycakes in ADO.NET days. How can I make the LINQ query run once and still databind to multiple controls?
Pseudocode:
var result = from c in dc.whatevers select c;
ddlItem1.DataSource = result;
ddlItem2.DataSource = result;
ddlItem3.DataSource = result;
Also:
var result = from c in dc.whatevers select c;
ddlItem1.DataSource = result.ToList();
ddlItem2.DataSource = result.ToList();
ddlItem3.DataSource = result.ToList();
Also:
List<whatever> result = (from c in dc.whatevers select c).ToList();
ddlItem1.DataSource = result;
ddlItem2.DataSource = result;
ddlItem3.DataSource = result;

The last option in your example is the easiest.
That will execute the query once, read it into memory, and use the in memory representation to bind to the controls
Calling ToList() should force query execution a single time. Using the resulting list should NOT repeat the query but load the values from the in memory collection. Are you positive that the code you're running is both what you have above and actually running the queries four times?

Try this:
var result = from c in dc.whatevers select c;
List<whatevers> resultList = result.ToList(); // Query runs here
ddlItem1.DataSource = new List<whatevers>(resultList); // Copy of the list
ddlItem2.DataSource = new List<whatevers>(resultList); // Copy of the list
ddlItem3.DataSource = new List<whatevers>(resultList); // Copy of the list

Related

Add new record to linq query result

I have a query as follows:
var paymentInfo =
from i in dbconnect.tblPayments
where i.tenderId == _tenderId
select i;
This query has some results, but I need to add an additional result that I already have, from the variable PaymentInfo.
For example suppose that my query has 2 results i need to add another result to "PaymentInfo" using linq.
I thought that the result is a kind of list, and that I could call .Add(PaymentInfo), but this doesn't work
How can I do this?
You can use Concat to concat another sequence to the end of this one.
var paymentInfo = paymentInfo.Concat(someOtherPayments);
I thought that the result is a kind of list
No, the result is an IEnumerable<T> which is read-only. You can create a list by calling .ToList() and then add an item to it.
var paymentInfo = (from i in dbconnect.tblPayments
where i.tenderId == _tenderId
select i).ToList();
paymentInfo.Add(existingPayment);

Getting total result count and allowing pagination in the same query with MongoDB

I have my query set up like so to allow for pagination. While this works, I have to basically run the same query twice to get the total matching results for the query AND allow for pagination. Is there any way to combine this into a single query?
public SearchResult GetResults()
{
//query is built elsewhere
var totalResults = (from i in Collection.Find(query)
select i).Count();
var results = (from i in Collection.Find(query)
select i)
.Skip(recordsToSkip)
.Take(recordsToTake)
.ToList();
//SearchResult is defined elsewhere
return new SearchResult
{
Results = results,
TotalResults = totalResults
};
}
First, to get the count you should not do a linq query and then count the results. This way enumerates all the results and then counts them, which is costly. You should instead use:
var totalResults = Collection.Find(query).Count()
This Count method is defined on the MongoCursor itself and will count the results in mongo, instead of in your .Net application.
I guess that was the real problem behind the question. But if you still want to unite the 2 queries you can do that like so:
var results = (from i in Collection.Find(query) select i).ToList();
var totalResults = results.Count();
var page = results
.Skip(recordsToSkip)
.Take(recordsToTake)
.ToList();
That will get the whole collection, count it, and return a page of it. I would not recommend you do that though, because you don't need the whole collection.
P.S: When you use Linq on the result of Find, it does the filtering in your application and not in the DB, so you should change your query to this one:
var results = Collection.Find(query)
.SetSkip(recordsToSkip)
.SetLimit(recordsToTake)
.ToList();

How to get total results count before .Take() - but when using .Take()

I am using .Take() to get a fixed number of results.
What is the best way to get the TotalCountBeforeTake (ie as if I didn't use the .Take())?
Can I get the TotalCountBeforeTake without running the query twice?
var Results = (from results in db.FindWords(term)
orderby results.word
select results.word).Take(100);
//just to get the total record count
int TotalCountBeforeTake = (from results in db.FindWords(term)
select results.word).Count();
// only showing 100 out of TotalCountBeforeTake results,
// but in order to know the TotalCountBeforeTake I had to run the query twice.
foreach (var result in Results)
{
Console.Write(result.ToString());
}
You want to query two things - the total number of items and a subset of items. So you need to run two queries:
// Define queries
var query1 = from results in db.FindWords(term)
orderby results.word
select results.word;
var query2 = query1.Take(100);
// Run queries
int totalCountBeforeTake = query1.Count();
foreach (var result in query2)
{
Console.Write(result.ToString());
}
I don't know of a way to get the count without splitting this up (hopefully someone else does) but in your situation I'd suggest:
//first get the records
var query = (from results in db.FindWords(term)
orderby results.word
select results.word).ToList();
//get the total record count
int TotalCountBeforeTake = query.Count();
// only showing 100 out of results,
foreach (var result in query.Take(100))
{
Console.Write(result.ToString());
}
IEnumerables and LINQ are used to create a selection chain. Before you actually start iterating, nothing is being executed (except for creating the selection chain).
This seems magic, as it drastically boosts performance, because trying to achieve the same with lists requires several iterations over the list(s).
But when you start iterating over an enumerable more than once, you are buying the elegance of LINQ with multiple operations which drops your performance benefit to zero and below.
In other words: convert your linq expression into an array and continue.
var Results = (from results in db.FindWords(term)
orderby results.word
select results.word).Take(100).ToArray();
Now you can count, iterate without performance loss.

Prevent new values from LINQ query

I have some data in a List I want to make a query against. In the meantime however, other users can add to this List and I get wrong items in return:
var query = from s in selected
where s.contains("www")
select s);
Then a user Can add item to selected list before The query is run, and I Will get this also. Can I prevent this behaviour?:
selected.add("123www")
foreach (var s in query)
/// gives me 123www
The var "query" just has the query assigned to it, but the query itself is first performed when the query is accessed in for example a foreach loop - hence you get the newly added data.
If you don't want this, you can use an extension method like "ToList()", where the collection stays the same:
var queryResultList = (from s in selected
where n.contains("www")
select s).ToList();
Here the ToList() iterates the collection immediately, and you can now iterate the queryResultList and get the right results and even though new elements arrive the output stays the same.
The query represents an action, which can be triggered any time you want
and it will yield different results if the source of data changed.
Just make a "snapshot" of the results at the time you desire to do so with a .ToArray():
var query = from s in selected
Where s.contains("www")
Select s)
string[] snapshot = query.ToArray();
When you call .ToList() or .ToArray() the query is executed. Therefore to avoid your problem you can write this code:
var query = from s in selected
where s.Contains("www")
select s);
var result = query.ToList();
selected.Add("123www");
foreach(var item in result)
{
/* You won't see "123www" */
}

Does multiple evaluations of an IQueryable object hit the Database multiple times?

In the Entity Framework, if I do the following:
var count = myIQueryable.Count();
var list = myIQueryable.ToList();
does that hit the Database twice? or just once?
In order to effectively count the number of entries, the framework needs to evaluate the query, thus hitting the Database. However, because the query may have changed between the Count() and ToList(), it must evaluate again. Consider the following:
var myIQueryable = my.db<SomeModel>(); // IQueryable<SomeModel>
var countQuery = myIQueryable.Count(); // 10
MakeAdditions(myIQueryable, 10); // adds 10 items
var list = myIQueryable.ToList(); // List<SomeModel> count=20
MakeAdditions(myIQueryable, 10);
var countList = list.Count(); // still 20, List never changed
Put another way, all calls against an IQueryable are still subject to the way it runs its queries. After capturing a query into a List, you are exclusively dealing with your in-memory List, independant of changes that occur to the IQueryable's data source.
Yes, it does hit the database twice, as both Count and ToList are eagerly evaluated. If you just want to access it once, do the following:
var list = myIQueryable.ToList();
var count = list.Count;

Categories