Get X records from complex LINQ query - linq

How can I get 10 records from complex LINQ query?
I tried to put .Skip(X).Take(10), but it doesn't work, depending on where I'm trying to take 10 it returns the full set of objects or nothing.
Setting .Skip(X).Take(10) at the end of the query doesn't what I'm looking for because of slow performance.
This is my query:
List<ReportReturn> report =
from var1 in context.Table1
join var2 in context.Table2
on var1.AccountID equals var2.AccountID
join var3 in context.Table3
on var1.AccountID equals var3.AccountID into all
where
var1.SubAccountID == intSubAccountID &&
// ...... and more conditions
let actual = var1.Total.GetValueOrDefault(0)
let Unique = var2.CountUnique
let Total = var2.Count
// ........ and more helper values
orderby var1.Date descending
from final in all.DefaultIfEmpty()
select new ReportReturn {
// ........................some property assigments
};

just writing
.Skip(X).Take(10)
will give you output in IEnumerable<T> type but yours is List<T> type.
So you should use
.Skip(X).Take(10).ToList()
in your case.

Related

Dynamic Linq on DataTable error: no Field or Property in DataRow, c#

I have some errors using Linq on DataTable and I couldn't figure it out how to solve it. I have to admit that i am pretty new to Linq and I searched the forum and Internet and couldn't figure it out. hope you can help.
I have a DataTable called campaign with three columns: ID (int), Product (string), Channel (string). The DataTable is already filled with data. I am trying to select a subset of the campaign records which satisfied the conditions selected by the end user. For example, the user want to list only if the Product is either 'EWH' or 'HEC'. The selection criteria is dynaically determined by the end user.
I have the following C# code:
private void btnClick()
{
IEnumerable<DataRow> query =
from zz in campaign.AsEnumerable()
orderby zz.Field<string>("ID")
select zz;
string whereClause = "zz.Field<string>(\"Product\") in ('EWH','HEC')";
query = query.Where(whereClause);
DataTable sublist = query.CopyToDataTable<DataRow>();
}
But it gives me an error on line: query = query.Where(whereClause), saying
No property or field 'zz' exists in type 'DataRow'".
If I changed to:
string whereClause = "Product in ('EWH','HEC')"; it will say:
No property or field 'Product' exists in type 'DataRow'
Can anyone help me on how to solve this problem? I feel it could be a pretty simple syntax change, but I just don't know at this time.
First, this line has an error
orderby zz.Field<string>("ID")
because as you said, your ID column is of type int.
Second, you need to learn LINQ query syntax. Forget about strings, the same way you used from, orderby, select in the query, you can also use where and many other operators. Also you'll need to learn the equivalent LINQ constructs for SQL-ish things, like for instance IN (...) is mapped to Enumerable.Contains etc.
With all that being said, here is your query
var productFilter = new[] { "EWH", "HEC" };
var query =
from zz in campaign.AsEnumerable()
where productFilter.Contains(zz.Field<string>("Product"))
orderby zz.Field<int>("ID")
select zz;
Update As per your comment, if you want to make this dynamic, then you need to switch to lambda syntax. Multiple and criteria can be composed by chaining multiple Where clauses like this
List<string> productFilter = ...; // coming from outside
List<string> channelFilter = ...; // coming from outside
var query = campaign.AsEnumerable();
// Apply filters if needed
if (productFilter != null && productFilter.Count > 0)
query = query.Where(zz => productFilter.Contains(zz.Field<string>("Product")));
if (channelFilter != null && channelFilter.Count > 0)
query = query.Where(zz => channelFilter.Contains(zz.Field<string>("Channel")));
// Once finished with filtering, do the ordering
query = query.OrderBy(zz => zz.Field<int>("ID"));

Linq to SQL not querying memory

I am using Linq for SQL and have always thought that I was querying the results of a Query in memory. I have just looked at the database and it is showing many thousands of queries rather than 1 which is what I expected.
My approach has been to run a query and then use linq to search within the resultset.
IQueryable<mapping> fieldList = from mm in db.mappings
join mi in db.metaItems on mm.secondaryMetaItemId equals mi.metaItemId
join mo in db.metaObjects on mi.metaObjectId equals mo.metaObjectId
where mm.linkageId == 277
select mm;
for (int i=0;i<100;i++)
{
mapping thisVar = fieldList.FirstOrDefault(m => m.primaryItem == info.Name);
}
How can I stop Linq requerying everytime I access my resultset...
Thanks for your help!
When you write a LINQ query, the query doesn't get actually get executed until you perform an action that actually enumerates over it (deferred execution). Calling FirstOrDefault() is an example of one such method that enumerates over the result (the first result has to be found). You'll want to call a method or otherwise enumerate over the results once. That way when you want to refer to those results throughout your program, you do it on a stored copy.
The easiest way you can do that is to convert it to a list. That will put the results in memory as a list. You could then use that.
IQueryable<mapping> fieldList =
from mm in db.mappings
join mi in db.metaItems on mm.secondaryMetaItemId equals mi.metaItemId
join mo in db.metaObjects on mi.metaObjectId equals mo.metaObjectId
where mm.linkageId == 277
select mm;
// save it!
var result = fieldList.ToList(); // query is processed only once here
// do stuff with result
for (int i=0;i<100;i++)
{
// using the stored result
thisVar = result.FirstOrDefault(m => m.primaryItem == info.Name);
}
try this :
var fieldList = (from mm in db.mappings
join mi in db.metaItems on mm.secondaryMetaItemId equals mi.metaItemId
join mo in db.metaObjects on mi.metaObjectId equals mo.metaObjectId
where mm.linkageId == 277
select mm).AsEnumerable();
foreach (int i=0;i<100;i++)
{
mapping thisVar = fieldList.FirstOrDefault(m => m.primaryItem == info.Name);
}

How to write LINQ IN clause query which will work as LIKE operator as well?

How we can write a LINQ query for following select sql query:
string brandid="1,2,3"
string bodystyleid="1,2,3"
-------------------
-----------------
select * from car
where brandid in (brandid)
and bodystyleid in (brandid)
----------------------
-------------------
My specific requirement is that if brandid or bodystyleid is blank(if user does not select
any checkbox of a particular search option) query should return all record for that particular where condition.
Please guide me.
Thanks,
Paul
In order to fulfil your requirement about returning all items if none are specified, you need to check for the lists being empty.
var brands = brandid.Split(',').Select(x => Int32.Parse(x));
var styles = bodystyleid.Split(',').Select(x => Int32.Parse(x));
var result = from c in car
where (!brands.Any() || brands.Contains(c.brandid))
&& (!styles.Any() || styles.Contains(c.bodystyleid))
select c;
(similar to sgmoore's solution, but includes the check for no brand/style specified)
I've not actually checked how this gets converted back to SQL - it may be more efficient to use a flag to indicate whether there are any values:
var brands = ....; // As above
bool anyBrands = brands.Any()
var result = from c in car
where (!anyBrands || brands.Contains(c.brandid))
.....
Is bodystyleid meant to check brandid or bodystyleid? (I am assuming bodystyleid, however have wrote the query to match the query in the question (brandid))
As a start you could do:
var results = (from c in car
where c.brandid.Contains(brandid)
&& c.bodystyleid.Contains(brandid)
select c).ToList();
var brandids = brandid .Split(',').Select(n => int.Parse(n)).ToList();
var bodyStyleids = bodystyleid.Split(',').Select(n => int.Parse(n)).ToList();
var results =
(from c in car where
brandids.Contains(c.brandid) &&
bodyStyleids.Contains(c.bodystyleid)
select c
).ToList();
the Ids you have are as strings with comma delimiter, you need them to be collections like List of the same type as your Ids of the Car table, so if brandid column is int then brandids has to be List<long>, then you can do
var results = (
from c in cars
where brandids.Contains(c.brandid) && bodystyleid.Contains(c.bodystyleid)
select c).ToList();

Datatable linq select query

I m trying to select a column's value from a datatable based on conditions.
var results = from DataRow myRow in dtCallBack.AsEnumerable()
where myRow.Field<DateTime>(1) == startDateTime
&& myRow.Field<int>(0) == callBackID
select myRow.Field<int>(3);
My datatable contains 4 columns ID,Date1,Date2,IntVal
I want to convert the variable results to int. (I want to return the column 4 IntVal)
var results = (from DataRow myRow in dtCallBack.AsEnumerable
where myRow.Field<DateTime>(1) == startDateTime
&& myRow.Field<int>(0) == callBackID
select myRow.Field<int>(3)).SingleOrDefault();
Well you've currently got an IEnumerable<int> by the looks of it. So which of those results do you want? What do you want to happen if there aren't any results?
If you're confident there's only a single result, you can use:
var result = results.Single();
If you want the first result or 0 if there aren't any, you could use
var result = results.FirstOrDefault();
If you want the first result and an exception if there aren't any, you could use
var result = results.First();
Basically there are lots of options, and you'll need to clarify your requirements before we can really give you a more concrete answer.

How can I get my orderby to work using an anonymous type?

What do I put in my order by?? I want to order by Name. I have moved the orderby after the distinct because I read that it needs to be done last.
var result = (from r in db.RecordDocs
where r.RecordID == recordID
select new
{
DocTypeID = r.Document.DocType.DocTypeID,
Name = r.Document.DocType.Name,
Number = r.Document.DocType.Number
}
).Distinct().OrderBy( );
Just do
.OrderBy(doc => doc.Name)
Another option, if you really prefer the query expression syntax would be to chain your query construction across multiple statements:
var query = from r in db.RecordDocs
where r.RecordID == recordID
select new
{
DocTypeID = r.Document.DocType.DocTypeID,
Name = r.Document.DocType.Name,
Number = r.Document.DocType.Number
};
query = query.Disctinct();
query = from doc in query orderby doc.Name select doc;
Since all of these methods are deferred, this will result in the exact same execution performance.

Resources