SQL Query
SELECT *
FROM tblOrders
WHERE CustomerId in (3455,4423,7655,1000)
LINQ Query
?
Say, I have an Array of IDs, then how do I search?
int[4] _ids;
_ids[0]=3455
_ids[1]=4423
_ids[2]=7655
_ids[3]=1000
var _orders = (from o in tblOrders
where (o.CustomerId in _ids[])
select o);
Above code is just for the example sake, I know it's wrong. But, is this possible?
No, it is not.
Try this one:
var _orders = from o in tblOrders
where _ids.Contains(o.CustomerId)
select o;
The keyword in you used, it is used for other purpose in C#. It is not like IN in SQL.
It is used in foreach statements. For instance:
foreach(var _id in _ids)
Console.WriteLine(_id);
Also, it is used as a generic modifier, for generic type parameters. For more documentation on the latter, please have a look here.
You can use the Contains method of the _ids array.
var _orders = from o in tblOrders
where _ids.Contains(o.CustomerId)
select o;
Use code as given below
List<Orders> lstOrders = new List<Orders>();
Orders objOrders;
for (int index = 1; index <= 10; index++)
{
objOrders = new Orders();
objOrders.OrderID = index;
objOrders.Order = "Order_" + index.ToString();
objOrders.CustomerID = index;
lstOrders.Add(objOrders);
}
int[] _customers = { 1, 2, 3, 4, 5 };
List<Orders> lstFilteredOrders = new List<Orders>();
lstFilteredOrders.AddRange(lstOrders.FindAll(x => _customers.Any(y =>y == x.CustomerID)));
Related
I have this class where the query must result in this list a property.
This property must check on table how many duplicated exists.
This code works, but its very slow. can you help me ?
var lst = _uow.Repository.GetAll();
var query =
from p in lst
select new GetRfqResponse
{
ID = p.ID,
//bad performance
Count = lst.Where(x => x.Property == p.Property).AsQueryable().Count(),
//
};
Counting in a queryable list can be easily achieved using the Count() function:
// Find duplicated names
var byName = from s in studentList
group s by s.StudentName into g
select new { Name = g.Key, Count = g.Count() };
Check this fiddle to see it running.
Below is for InMemory
GroupBy should come to help.
var propertyGroupedList = list.GroupBy(l=>l.Property);
var query = list.Select(l => new GetRfqResponse{
Id = l.Id,
Count = propertyGroupedList.First(g=> g.Key == l.Property).Count()
});
Or you can create a dictionary with key as "Property" and value as count, then you will have to loop just once to store the count.
This allows you to get count in constant time
Dictionary<string, int> map = new Dictionary<string, int>();
foreach (var item in lst)
{
if (!map.ContainsKey(lst.Property))
{
map.Add(item.Property, 1);
}
else
map[item.Property]++;
}
var z = lst.Select(l => new GetRfqResponse{
Id = l.ID,
Count = map[l.Property]
});
I have a linq statement similar to the following:
var entities = from row in table.AsEnumerable()
select new
{
ID = row.ID,
X = GetObjectByProcessingID(row.ID)[0],
Y = GetObjectByProcessingID(row.ID)[1],
....
};
Would it be possible to do something like:
var entities = from row in table.AsEnumerable()
select new
{
private var tmp = GetObjectByProcessingID(row.ID),
ID = row.ID,
X = tmp[0],
Y = tmp[1],
....
};
To avoid calling GetObjectByProcessingID twice?
I know you can do something like:
var entities = from row in table.AsEnumerable()
select new
{
ID = row.ID,
XAndY = GetObjectByProcessingID(row.ID),
....
};
But in this case, it will expose the whole array. I also know that I can implement stuff like caching on the method side (GetObjectByProcessingID) or creating a helper method to call it and remember the last value if the ID is the same. But is there a better way? Can I create temporary variables while creating the anonymous type?
Use the let keyword like this:
var entities = from row in table.AsEnumerable()
let tmp = GetObjectByProcessingID(row.ID)
select new {
ID = row.ID,
X = tmp[0],
Y = tmp[1],
....
};
You can also try using method syntax which is very favorite to me:
var entities = table.AsEnumerable()
.Select(row => {
var tmp = GetObjectByProcessingID(row.ID);
return new {
ID = row.ID,
X = tmp[0],
Y = tmp[1],
....
};
});
Is there way to rewrite:
var tbl = ds.TABLES;
var q = from c in tbl
select c.TABLE_TYPE;
string s = "";
foreach (var item in q.Distinct())
{
s += "[" + item + "]";
}
MessageBox.Show(s);
So that the Distinct() call is in the LINQ query?
There is no Distinct() method syntax in the language integrated query syntax. The closest you could do would be to move the current call:
var q = (from c in tbl
select c.TABLE_TYPE).Distinct();
The Distinct extension method in LINQ does not have a query syntax equivalent.
See https://learn.microsoft.com/en-us/archive/blogs/charlie/linq-farm-using-distinct-and-avoiding-lambdas for additional information as to why.
(from c in tbl select c.TABLE_TYPE).Distinct();
VB has this functionality if you place the distinct after select.
You may capture HashSet and put where clause before select:
var hs = new HashSet<char>();
from c in "abcabcd"
where hs.Add(c)
select c;
In the search for a Distinct-function for LINQ upon finding this question and realizing it doesn't exist, my workaround is by using GroupBy().
The obvious problem is that the distinct-set doesn't contain all the data (say you have three fields but only want to distinct on two fields missing out on the value for the last field, but, then again, DISTINCT in t-sql works the same way).
LINQ-code (hence the Dump):
void Main()
{
var gt = new GenerateThings();
var dlist = gt.list();
dlist.Dump();
dlist.GroupBy(x => new {x.id, x.cat}).Dump();
}
public class model
{
public int id {get;set;}
public int cat {get;set;}
public int type {get;set;}
}
public class GenerateThings
{
public List<model>list()
{
var dlist = new List<model>();
dlist.Add(createNew(1, 1, 1));
dlist.Add(createNew(1, 1, 1));
dlist.Add(createNew(1, 2, 1));
dlist.Add(createNew(1, 2, 1));
dlist.Add(createNew(1, 1, 2));
dlist.Add(createNew(1, 1, 2));
dlist.Add(createNew(1, 1, 2));
return dlist;
}
private model createNew(int id, int cat, int type){
return new model{
id = id,
cat = cat,
type = type
};
}
}
LINQ-dump result
I have a query that sums and aggregates alot of data something like this:
var anonType = from x in collection
let Cars = collection.Where(c=>c.Code == "Cars")
let Trucks = collection.Where(c=>c.Code == "Trucks")
select new {
Total = collection.Sum(v=>v.Amount),
CarValue = Cars.Sum(v=>v.Amout),
TruckValue = Trucks.Sum(v=>v.Amount),
CarCount = Cars.Count(),
TruckCount = Trucks.Count()
};
I find it really weird that I have to declare the range variable x, especially if I'm not using it. So, am I doing something wrong or is there a different format I should be following?
I could be wrong, but from your usage, I don't think you want to do a traditional query expression syntax query with your collection anyway, as it appears you are only looking for aggregates. The way you have it written, you would be pulling multiple copies of the aggregated data because you're doing it for each of the items in the collection. If you wished, you could split your query like this (sample properties thrown in)
var values = collection.Where(c => c.Code == "A");
var anonType = new
{
Sum = values.Sum(v => v.Amount),
MinimumStartDate = values.Min(v => v.StartDate),
Count = values.Count()
};
You declare a range variable no matter the looping construct:
foreach(var x in collection)
or
for(var index = 0; index < collection.Count; index++)
or
var index = 0;
while(index < collection.Count)
{
//...
index++;
}
Queries are no different. Just don't use the variable, it doesn't hurt anything.
So, am I doing something wrong?
Your query is not good. For each element in the collection, you are enumerating the collection 5 times (cost = 5*n^2).
Is there a different format I should be following?
You could get away with enumerating the collection 5 times (cost = 5n).
IEnumerable<X> cars = collection.Where(c => c.Code == "Cars");
IEnumerable<X> trucks = collection.Where(c => c.Code == "Trucks");
var myTotals = new
{
Total = collection.Sum(v => v.Amount),
CarValue = cars.Sum(v => v.Amount),
TruckValue = trucks.Sum(v => v.Amount,
CarCount = cars.Count(),
TruckCount = trucks.Count()
};
How do I embed the ordinal number of element as its attribute in this linq query.
var AllSections = from s in xmlDoc.Descendants("section")
select new
{
id = s.Attribute("id").Value,
themeTitle = s.Element("themeTitle").Value,
themeText = s.Element("themeText").Value,
objects = (from a in AllObjects
join b in s.Descendants("object")
on a.Attribute("accessionNumber").Value equals
b.Attribute("accessionNumber").Value
//select a
select new
{
//index = insert ordinal id/index of element
ObjectTitle = a.Element("ObjectTitle").Value,
ObjectText = a.Element("textentry").Value,
}
)
};
You can't easily do it with a query expression - at least not without a horrible side effect. However, you can easily do it with dot notation for either Select or Where. Given that you've got quite a long query expression, it's probably easiest to embed an extra call to where at the start - assuming you do actually want the index of "s" in the original expression:
var AllSections =
from s in xmlDoc.Descendants("section")
select new
{
id = s.Attribute("id").Value,
themeTitle = s.Element("themeTitle").Value,
themeText = s.Element("themeText").Value,
objects = (from a in AllObjects.Select((Item,Index) => new {Item,Index})
join b in s.Item.Descendants("object")
on a.Item.Attribute("accessionNumber").Value equals
b.Attribute("accessionNumber").Value
//select a
select new
{
//index = insert ordinal id/index of element
Index = a.Index,
ObjectTitle = a.Element("ObjectTitle").Value,
ObjectText = a.Element("textentry").Value,
}
)
};
That's assuming you want the index of a within AllObjects.
#Jon Skeet gave you the appropriate overload of Select to use, and here is it in your query:
var AllSections = from s in xmlDoc.Descendants("section")
select new
{
id = s.Attribute("id").Value,
themeTitle = s.Element("themeTitle").Value,
themeText = s.Element("themeText").Value,
objects = (from a in AllObjects
join b in s.Descendants("object")
on a.Attribute("accessionNumber").Value
equals b.Attribute("accessionNumber").Value
select a).Select((a, index) =>
new
{
Index = index,
ObjectTitle = a.Element("ObjectTitle").Value,
ObjectText = a.Element("textentry").Value,
})
};