linq in or contains? - linq

How can I use Linq-to-sql to a search like this:
where obj.id equals any of the following {1,2,3,4}
I would guess I could use the in or perhaps contains?
where obj.id in Enumerable.Range( (int) myEnum.Start, (int) myEnum.End) ) ?

You can use .Contains(), like this:
var list = new List<int> { 1, 2, 3, 5 };
var result = from s in DB.Something
where list.Contains(s.Id)
select s;
This will get translated to a parameterized form of:
WHERE Id IN (1, 2, 3, 5)

var myCustomers = new short[] {1,2,3,4};
var foo = db.Customers.Where(c=> myCustomers.Contains(c.ID));

Related

Filter LINQ query using items from an external list with Lambda

How do you rewrite this in lambda?
int[] productList = new int[] { 1, 2, 3, 4 };
var myProducts = from p in db.Products
where productList.Contains(p.ProductID)
select p;
Assuming that by "with lambda" you mean the "query syntax", you can rewrite your query like this:
var myProducts = db.Products.Where(p => productList.Contains(p.ProductID));
Same thing just move the logic within a Where call.
var myProducts = db.Products.Where(p => productList.Contains(p.ProductID));
http://msdn.microsoft.com/en-us/library/vstudio/bb397947.aspx
^ a quick read that compares query syntax to method syntax for a query to two.

LINQ Get Grouped ID by condition

Hi I have a List so:
A 1
A 2
A 3
A 4
B 1
B 2
C 1
I want to select the letter that contains AT LEAST these 3 numbers: 1,2,3
So in this case would be selected the letter A.
Can you help me to write this as LINQ expression?
Thanks a lot!
First, make a collection of the numbers you require.
var required = new[] { 1, 2, 3 };
Then, group your pairings by letter.
var groupedPairings = pairings.GroupBy(p => Letter, p => Number);
Then, discard those pairings that don't have your three required items. (The logic here is "take the collection of required items, remove anything in the group, and make sure there is nothing left".)
var groupsWithRequired = groupedPairings
.Where(g => !required.Except(g).Any());
Now, if you just want the letters, you can simply do
var lettersWithRequired = groupsWithRequired.Select(g => g.Key);
or if you want a dictionary mapping from the letter to its collection of numbers, you can do
var dictionary = groupsWithRequired.ToDictionary(g => g.Key, g => g.ToArray());
var numbersForA = dictionary["A"]; // = {1, 2, 3, 4}
You could try this, although I don't feel it's the best answer:
var items = new List<Item>{
new Item{Name="A", Value=1},
new Item{Name="A", Value=2},
new Item{Name="A", Value=3},
new Item{Name="A", Value=3},
new Item{Name="A", Value=4},
new Item{Name="B", Value=1},
new Item{Name="B", Value=2},
new Item{Name="C", Value=1},
};
var values = new List<int>{1,2,3};
var query = items.GroupBy (i => i.Name)
.Where (i => i.Select (x => x.Value)
.Intersect(values).Count() == values.Count)
.Select (i => i.Key);
Where
class Item{
public string Name{get;set;}
public int Value{get;set;}
}

Filter Enums based on List in LINQ

I Have a Enum
public enum ProcessStatus: byte
{
NotStarted = 0,
PreCheckStarted= 1,
PreCheckCompleted= 2,
Processing= 3,
Failed= 4,
Completed= 5,
Closed= 6
}
in Table we have entries like 0,3,5,6
we need list of Enums based on some criteria and criteria is List which contains 0,1,2
i am able to get all Enums as List Like
Enum.GetValues(typeof(ProcessStatus)).OfType<ProcessStatus>()
and have
List<byte> processListIDs
which contains IDs
i want
IEnumerable<ProcessStatus> filtered based on ids in processListIDs using LINQ.
Thanks in Advance
You can use Intersect with better performance:
var enumList = Enum.GetValues(typeof (ProcessStatus))
.OfType<ProcessStatus>().Cast<byte>();
var result = enumList.Intersect(processListIDs)
.Cast<ProcessStatus>();
var res =
processStatusCollection.Where(item => processListIDs.Contains((int)item));
You could use Enum.TryParse<TEnum>:
List<byte> processListIDs = new List<byte>() { 0, 3, 5, 6 };
ProcessStatus ps = ProcessStatus.NotStarted;
IEnumerable<ProcessStatus> status = processListIDs
.Where(p => Enum.TryParse<ProcessStatus>(p.ToString(), out ps))
.Select(p => ps);
Try this,
var p = new List<byte>() { 1, 2, 3, 4, 6 };
IEnumerable<ProcessStatus> result = p.Select(o => (ProcessStatus)Enum.Parse(typeof(ProcessStatus), o.ToString()));
/// do something with result

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());

Row number in LINQ

I have a linq query like this:
var accounts =
from account in context.Accounts
from guranteer in account.Gurantors
where guranteer.GuarantorRegistryId == guranteerRegistryId
select new AccountsReport
{
recordIndex = ?
CreditRegistryId = account.CreditRegistryId,
AccountNumber = account.AccountNo,
}
I want to populate recordIndex with the value of current row number in collection returned by the LINQ. How can I get row number ?
Row number is not supported in linq-to-entities. You must first retrieve records from database without row number and then add row number by linq-to-objects. Something like:
var accounts =
(from account in context.Accounts
from guranteer in account.Gurantors
where guranteer.GuarantorRegistryId == guranteerRegistryId
select new
{
CreditRegistryId = account.CreditRegistryId,
AccountNumber = account.AccountNo,
})
.AsEnumerable() // Moving to linq-to-objects
.Select((r, i) => new AccountReport
{
RecordIndex = i,
CreditRegistryId = r.CreditRegistryId,
AccountNumber = r.AccountNo,
});
LINQ to objects has this builtin for any enumerator:
http://weblogs.asp.net/fmarguerie/archive/2008/11/10/using-the-select-linq-query-operator-with-indexes.aspx
Edit: Although IQueryable supports it too (here and here) it has been mentioned that this does unfortunately not work for LINQ to SQL/Entities.
new []{"aap", "noot", "mies"}
.Select( (element, index) => new { element, index });
Will result in:
{ { element = aap, index = 0 },
{ element = noot, index = 1 },
{ element = mies, index = 2 } }
There are other LINQ Extension methods (like .Where) with the extra index parameter overload
Try using let like this:
int[] ints = new[] { 1, 2, 3, 4, 5 };
int counter = 0;
var result = from i in ints
where i % 2 == 0
let number = ++counter
select new { I = i, Number = number };
foreach (var r in result)
{
Console.WriteLine(r.Number + ": " + r.I);
}
I cannot test it with actual LINQ to SQL or Entity Framework right now. Note that the above code will retain the value of the counter between multiple executions of the query.
If this is not supported with your specific provider you can always foreach (thus forcing the execution of the query) and assign the number manually in code.
Because the query inside the question filters by a single id, I think the answers given wont help out. Ofcourse you can do it all in memory client side, but depending how large the dataset is, and whether network is involved, this could be an issue.
If you need a SQL ROW_NUMBER [..] OVER [..] equivalent, the only way I know is to create a view in your SQL server and query against that.
This Tested and Works:
Amend your code as follows:
int counter = 0;
var accounts =
from account in context.Accounts
from guranteer in account.Gurantors
where guranteer.GuarantorRegistryId == guranteerRegistryId
select new AccountsReport
{
recordIndex = counter++
CreditRegistryId = account.CreditRegistryId,
AccountNumber = account.AccountNo,
}
Hope this helps.. Though its late:)

Resources