How to parameterize a linq query? - linq

I've got a data structure that is a list of hash tables, like so:
List<Hashtable> lh = new List<Hashtable>();
And a fairly simple LINQ query for this container:
var query = from h in lh where h["foo"] == "bar" select h;
Is there a way to parameterize the where clause? Something like:
var where_clause = where h["foo"] == "bar";
var query = from h in lh where_clause select h;

Depends on what exactly you're trying to accomplish, but yes you can:
Func<List<Hashtable>, bool> where_clause = h => h["foo"] == "bar";
List<Hashtable> lh = new List<Hashtable>();
var query = lh.Where(where_clause);

Related

Executing list of IEnumerable queries

I have multiple Link queries loading to a IEnumerable list
var queries = new List<IEnumerable<Customers>>();
queries.Add(from c in context.Customers where c.region = 'NE' select c);
queries.Add(from c in context.Customers where c.region = 'SW' select c);
//want count of customers in those two regions
var result = queries.Sum(q => Count());
However it is returning a count of the queries (2), not count of the Customers.
How can execute the List of IEnumerable queries?
The mistake is at the last line:
q => Count()
Instead of actually counting the elements in a sequence, which would be q => q.Count(), you are calling a method Count() of either a current instance or the current class.
Actually, there is no need to do two separate queries. Instead, use a single query:
var query = from c
in context.Customers
where c.region = 'NE' || c.region = 'SW'
select c;
var result = query.Count();
or, slightly shorter:
var result = context.Customers.Count(c => c.region = 'NE' || c.region = 'SW');

Can we write Update statement in linq?

can we write update statement in linq?
example:
var query = Update customer set isEdit = 1 where id = 1
Thanks
No, you can't. The Q in LINQ stands for Query.
What you can do is the following:
foreach(var c in customer.Where(x => x.Id == 1))
c.isEdit = 1;
You can shortcut the updates by doing a 'looks like Linq' query, using the ForEach method of the class List:
var toUpdate = customer.Where(c => c.id == 1).ToList();
toUpdate.ForEach(c => c.isEdit = 1);
Yes you can, see my answer here.
Foo foo=new Foo { FooId=fooId }; // create obj and set keys
context.Foos.Attach(foo);
foo.Name="test";
context.SubmitChanges();
In your Dbml set UpdateCheck="Never" for all properties.
This will generate a single update statement without having to do a select first.

How can I define a List to add results of a query in a loop?

I have an array filled with long type values and for each value in the array I need to implement a query. I used foreach loop as you can see from the code below:
var result;
foreach(long id in PrdIdArr)
{
var mainQuery = (from o in db.OPERATIONs
join u in db.UNITs on o.OP_UNIT_ID equals u.UNIT_ID into smt
from s in smt
join x in db.XIDs on s.UNIT_ID equals x.UNIT_ID
where o.OP_OT_CODE == OtCode
where x.IDTYP_CD == "BSN"
where s.START_PRD_ID == id
where o.OP_UPD_DATE >= _StartDate
where o.OP_UPD_DATE <= _EndDate
select new
{
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}).Take(_RowNumber);
//var result = mainQuery.ToList();
result.add(mainQuery.ToList());
}
data = this.Json(result);
data.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return data;
However, I have a problem in my code; I have to define a main list just before the foreach loop so that I could add results of each query to the that main list. my question is: How can I define this list as you can see at the beginning of my code? Thanks for the help...
How can I define this list as you can see at the beginning of my code?
Make
new {
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}
into a concrete type (say QueryResult, although something a little more specific than that), and then just declare
var result = new List<QueryResult>();
Also, you should consider turning
foreach(long id in PrdIdArr)
and
where s.START_PRD_ID == id
into
where PrdIdArr.Contains(s.Start_PRD_ID)
var result = new List<object>();
foreach(long id in PrdIdArr)
{
....
result.Add(mainQuery.ToList());
}
You could do this:
var result = PrdIdArr.Select(id =>
from o in db.OPERATIONs
join u in db.UNITs on o.OP_UNIT_ID equals u.UNIT_ID into smt
from s in smt
join x in db.XIDs on s.UNIT_ID equals x.UNIT_ID
where o.OP_OT_CODE == OtCode
where x.IDTYP_CD == "BSN"
where s.START_PRD_ID == id
where o.OP_UPD_DATE >= _StartDate
where o.OP_UPD_DATE <= _EndDate
select new
{
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}
.Take(_RowNumber)
.ToList()
).ToList();
I highly recommend performing some Extract Method refactorings, as the code is pretty complex and hard to understand/mange this way.
Just create the anonymous type outside with the same property names and the correct type
var result = Enumerable.Range(0, 0).Select(x => new
{
OP_ID = 1,
OP_UPD_DATE = DateTime.Now,
EXTERNAL_ID = 1,
OP_OS_CODE = 1,
OP_START = DateTIme.Now,
OP_ST_STATION = "",
START_PRD_ID = 1,
}).ToList();
And in your loop call AddRange
result.AddRange(mainQuery.ToList());

conditional assignments in Linq to SQL methods

How do I do something like the following, assinging new values based on condition within a linq method but keeping all results.
int x= 100;
var results= from r in Results where r.id==id select r
{ if r.value==x set r.result="Found"}
You're not really meant to - ideally queries shouldn't have side effects. I mean you can do:
var results = Results.Where(r => r.id == id)
.Select(r => {
if (r.value == x)
{
r.result = "Found";
}
return r;
};
I'd generally try not to though...
Note that this really won't work in LINQ to SQL etc.
It's probably better to make a second pass so you can keep your query clean and side-effect-free.
int x = 100;
List<Result> results = (from r in Results
where r.id == id
select r).ToList();
results.ForEach(r => r.result = r.value == x ? "Found" : "Not Found");
Linq should not be used in that way. I would iterate over the results of the query and then change them.
var results= from r in Results where r.id==id select r;
foreach (var r in results.ToList()) { if (r.value==x) r.result="Found"; }

Is there a better way to code this LINQ fragment?

I have this fragment of code:
SmsDataClassesDataContext dc = new SmsDataClassesDataContext();
// Get the customer
Customer currentCustomer = dc.Customers.Single( c => c.Hash1 == forThisHash );
// Get from Name (LINQ to XML)
var q = from c in thisSmsPack.Descendants("from")
select c;
string from = q.First().Value;
foreach ( XElement element in thisSmsPack.Descendants("to") )
{
// Create the queue
SmsQueue sq = new SmsQueue();
sq.CustomerId = currentCustomer.CustomerId;
sq.MsgFrom = from;
sq.MsgTo = element.Attribute("name").Value;
sq.MsgPhone = element.Attribute("phone").Value;
sq.MsgBody = element.Attribute("msg").Value;
sq.Priority = currentCustomer.SendsSmsAtPriority;
sq.DontSendUntil = GetNextSendDate();
// sq.TimeCreated = System.DateTime.Now;
currentCustomer.SmsQueues.Add(sq);
}
dc.SubmitChanges();
I am creating new instances of "SmsQueues", populating the values and when the foreach loop is finished I submit the changes. Given the new lambda/linq/anonymous types that .NET 3.5 has, is there a more "modern" way to accomplish the above?
As a side question, maybe related, can I return an existing type composed of different columns in the select part of the linq expression?
Suppose you have three tables:
T1 == T1.Id, T1.Name
T2 == T2.Id, T2.Phone
T3 == T3.Name, T3.Phone, T3.SomethingElse
Can I perform a LINQ query that returns:
T1.Name, T2.Phone, SomethingElseNew
And let .NET know that that is of Type T3 (and it's a new instance of it)?
That way when I SubmitChanges, new T3 instances are inserted in the DB?
I don't know if I make myself clear :S
I don't have a system available to test this, but I think this (or something very close) should work.
CustomerId = currentCustomer.CustomerId;
var sqrange = from element in thisSmsPack.Descendants("to") )
select new SmsQueue
{
// Create the queue
MsgFrom = from,
MsgTo = element.Attribute("name").Value,
MsgPhone = element.Attribute("phone").Value,
MsgBody = element.Attribute("msg").Value,
Priority = currentCustomer.SendsSmsAtPriority,
DontSendUntil = GetNextSendDate()
// TimeCreated = System.DateTime.Now
};
currentCustomer.SmsQueues.AddRange(sqrange);
EDIT: Fixed the numerous syntax errors (as delineated in the comments)
You could do something like this (syntax may be off slightly, no intellisense here):
var q = T1.Join(T2, t => t.Id, t2 => t2.Id)
select new T3{Name=t.Name,Phone=t2.Phone,SomethingElseNew="Chickens"};

Resources