LINQ: analog for sql's EXISTS? - c#

Let's say I have a few people in a collection "Employees":
Name | Position | Age
------+----------+----
Tom | Manager | 35
Hank | Driver | 38
Harry | Driver | 45
... | ... | ...
Mark | Driver | 30
----------------------
and I want to get all Drivers if there is at least one among them who's older that 40 years old.
Could you help me to complete my LINQ?
UPD. I'd like to do this task using a single LINQ and perfomance has no matter. So decision
var allDrivers = Employees.Where(n => n.Position == "Driver").ToList();
return allDrivers.Any(n => n.Age > 40)
? allDrivers
: new List<Employee>();
is good, but I can't mark it as an answer.
In this particular case I need to get Hank, Harry and Mark. Because all they're drivers and Harry is 45 (>40). But if Harry was 39 I would get nothing as a result because in this case all drivers were under 40.

So if I were to parse "I want to get all Drivers if there is at least one among them who's older that 40 years old" literally, it'd be
var allDrivers = Employees.Where(n => n.Position == "Driver").ToList();
return allDrivers.Any(n => n.Age > 40)
? allDrivers
: new List<Employee>();
Or something similar.
For one-query functional craziness:
(int maxAge, List<Employee> result) = Employees
.Aggregate(
(age: 0, list: new List<Employee>()),
(al, n) => n.Position == "Driver"
? (Math.Max(al.age, n.Age), al.list.Concat(new [] {n}).ToList()
: al));
return maxAge > 40 ? result : new List<Employee>();
This is just PoC that you CAN. But remember - when asking yourself if you could, don't forget to ask yourself if you should :)

If you really want it inside one statement (this feels very artificial to me) then you can do this:
IEnumerable<Employee> result =
employees.GroupBy(n => n.Position)
.Where(g => g.Key == "Driver" && g.Max(x => x.Age) > 40)
.FirstOrDefault();
Don't forget to do
return result ?? Enumerable.Empty<Employee>();
if you want to return an empty result instead of null when nothing is found.

Related

Find the first free id

One of my small database management projects (written in delphi) used sql queries to find the first free id of mysql table.
Example: I have to find the first free id (hole) in a table like this:
| id | Col1 |
|------|------|
| 5101 | ABC |
| 5102 | BCD |
| 5103 | CDE |
| 5105 | EFG | 🡔 first missing id
| 5106 | GHI |
| 5108 | ILM |
The code should find the first free id 5104
Here's how I'd do it in SQL (in old project):
SELECT
MIN((doc.id + 1)) AS nextID
FROM (doc
LEFT JOIN doc doc1
ON (((doc.id + 1) = doc1.id)))
WHERE (ISNULL(doc1.id) AND (doc.id > 5000))
Now, which I am rewriting in c # language, I need to convert sql statements into a LINQ query (which uses Devart dotConnect for mysql Entity Framework).
Starting from here:
DC db = new DC();
var nums = db.Documentos.OrderBy(x => x.Id);
From Can LINQ be used to find gaps in a sorted list?:
var strings = new string[] { "7", "13", "8", "12", "10", "11", "14" };
var list = strings.OrderBy(s => int.Parse(s));
var result = Enumerable.Range(list.Min(), list.Count).Except(list).First(); // 9
Basically, order the list. Then create an array of sequential numbers (1,2,3...) from the minimum all the way to the max. Check for missing values in the list, and grab the first one. That's the first missing number.
This can give you all gaps within your table
var nums= (new List<int> (){1,2,3,25,4,5,6,7,8, 12, 15,21,22,23}).AsQueryable();
nums
.OrderBy(x => x)
.GroupJoin(nums, n=> n + 1, ni => ni, (o,i)=> new {o, i})
.Where(t=> !(t.i is IGrouping<int, int>))
.Dump();
.Net Fiddle
Another method (similar to what you're using now).
Assume you have an array of integers (or another type of collection) like this:
var myIDs = new int[] { 5101, 5113, 5102, 5103, 5110, 5104, 5105, 5116, 5106, 5107, 5108, 5112, 5114, 5115 };
If it's not already ordered, the OrderBy() it:
myIDs = myIDs.OrderBy(n => n).ToArray();
Extract the first number that is less than (next number) + 1:
int result = myIDs.Where((n, i) => (i < myIDs.Length - 1) && (n + 1 < myIDs[i + 1])).FirstOrDefault();
If none of the members of this collection satisfy the condition, take the last one and add 1:
result = result == default ? myIDs.Last() + 1 : result;

how to avoid two columns contain 0 in linq

assume as i have to shown the list of value in the screen
iam taking the list using linq
Student English Hindi Tamil MArathi
------- --------- ------- ------- ---------
Deepan 56 65 34 45
Mohan 45 34 0 23
Murali 56 89 0 0
Assume that i have these values in db.....
I dont want to show if (tamil and marathi ) is 0.....if both r contains 0 means ....
i have to avoid that row while taking from database using linq ...eg(murali)...but i dont want to avoid Mohan.....pls give me the linq query
Now i tried this
var ulist = (from c in CustomerTransactions
where c.TransTypeID==12
select new
{
Student=c.Student,
English=c.English,
Hindi=c.Hindi,
Tamil=c.Tamil,
Marathi=c.Marathi
}).ToList().OrderBy(b => b.Student).Where(x => x.Marathi!=0 );
You can combine several conditons in a single where-statement:
.Where(x => x.Marathi !=0 && x.Tamil != 0)
This will select only those entries where both conditions pass (meaning both Marathi and Tamil are not 0).
This is what you can use if Lambda is fine for you. You can combine all the 3 checks in first Where clause itself, instead of specifying the conditions at 2 different places.
CustomerTransactions.Where(c => c.TransTypeID==12 && !(c.Marathi == 0 && c.Tamil == 0))
.OrderBy(c => c.Student)
.Select(c => new {
Student=c.Student,
English=c.English,
Hindi=c.Hindi,
Tamil=c.Tamil,
Marathi=c.Marathi
}).ToList();

LINQ to SQL selective choosing of fields from a group

I have a LINQ to SQL query which at one point, returns two rows which I'd like to group by ID and select specific fields, lets say something like this:
ID | Field1 | Field2 | Field3
-----------------------------
1 | 2 | null | 4
1 | 3 | 5 | null
What's unusual about this query is that from the group, I want to select something like this:
ID | Field1 | Field2 | Field3
-----------------------------
1 | 2 | 5 | 4
Note that the group selects fields from both records. Also note that it's not a simple null coalesce type operation as I need to be able to select a Field1 of 2 or 3 based on some other factors (another field).
Is there a clever way I can project into a new type whilst selecting specific fields as I want them?
I'm working on an IQueryable at this point, so I need a solution which translates into SQL, previously the query did something like this:
.Select(x => new MyObject {
Field1 = myGroup.First(x => x.Field4 == 1).Field1,
Field2 = myGroup.FirstOrDefault(x => x.Field4 == 1) == null ? myGroup.FirstOrDefault(x => x.Field4 == 2).Field2 : myGroup.FirstOrDefault(x => x.Field4 == 1).Field2
});
Which doesn't work as it can't work out what to with the operations.
I think we might be resigned to selecting some combination object with all the fields denormalised and then selecting from LINQ to objects in memory, but I'd rather have the DB do the work if possible.
What you need to do is write the C#/LINQ expression to generate a SQL CASE statement.
Generally speaking a case statement is written:
M = CASE
WHEN A == P THEN V
WHEN B == Q THEN W
WHEN C == R THEN X
WHEN D == S THEN Y
ELSE Z
END
In these examples all the letters A = P to D = S, and V to Z can be any expression of any complexity. So for example you can say WHEN a.cost > 1.5 * b.estimate THEN c.bestoffer.
To generate that exact case statement you need the following LINQ/C#:
M =
(
A == P? V :
B == Q? W :
C == R? X :
D == S? Y :
Z
)
So to attack your (unstated) problem directly, you can write arbitrary conditions for the values of each field, using ternary operators and these will be converted to LINQ CASE statements.
See also (and credit to) to the following:
http://www.codeproject.com/Articles/38264/How-to-Create-T-SQL-CASE-Statements-With-LINQ-To-S
linq case statement
If I understand what you're asking for, should be something like this:
from g in (from entity in db.Entities
group entity by entity.Id)
select new
{
Id = g.Key,
Field1 = g.Select(e => e.Field1)
.FirstOrDefault(f => null != f),
Field2 = g.Select(e => e.Field2)
.FirstOrDefault(f => null != f),
Field3 = g.Select(e => e.Field3)
.FirstOrDefault(f => null != f),
}
Note that if – for any given Fieldx – there is no non-null value of that field within that group, the resultant Fieldx value will be null.

Search on all fields of an entity

I'm trying to implement an "omnibox"-type search over a customer database where a single query should attempt to match any properties of a customer.
Here's some sample data to illustrate what I'm trying to achieve:
FirstName | LastName | PhoneNumber | ZipCode | ...
--------------------------------------------------
Mary | Jane | 12345 | 98765 | ...
Jane | Fonda | 54321 | 66666 | ...
Billy | Kid | 23455 | 12345 | ...
If the query was "Jane", I'd expect row #1 to be returned as well as row #2.
A query for 12345 would yield rows #1 and #3.
Right now, my code looks pretty much like this:
IEnumerable<Customer> searchResult = context.Customer.Where(
c => c.FirstName == query ||
c.LastName == query ||
c.PhoneNumber == query ||
c.ZipCode == query
// and so forth. Fugly, huh?
);
This obviously works. It smells like really bad practice to me, though, since any change in the Entity (removal of properties, introduction of new properties) would break stuff.
So: is there some LINQ-foo that will search across all properties of whatever Entity I throw at it?
first find all properties within Customer class with same type as query:
var stringProperties = typeof(Customer).GetProperties().Where(prop =>
prop.PropertyType == query.GetType());
then find all customers from context that has at least one property with value equal to query:
context.Customer.Where(customer =>
stringProperties.Any(prop =>
prop.GetValue(customer, null) == query));

Linq-to-entities: Easy to find max value in SQL, but difficult in LINQ?

I've started using Linq-to-entities with .NET 3.5, and I've come across a scenario that I can do real easy in SQL, but I'm having great difficulty with linq.
I have a table in a SQL database with three fields, for purposes of this example I'll call them foo, bar, and foo_index and populate them like so:
Blockquote
foo | bar | foo_index
555 101 1
555 101 2
555 101 3
555 101 4
555 101 5
To get what bar is at the max foo_index where foo=555 the SQL is
SELECT bar, max(foo_index) as max_foo_index
FROM T
WHERE foo=555
GROUP BY bar
I've written some linq-to-entities code in C# that works, but I have a feeling there is a much more elegent solution out there, and that I'm missing some concept that would make the following much easier. Also, is there any way other then a foreach to get the data out of a var?
db_entity db = new db_entity();
var q =
from table in db.T
where table.FOO == 555
select new { table.BAR, table.FOO_INDEX };
var q2 =
from t2 in q
where t2.FOO_INDEX == table.Max(r => r.FOO_INDEX)
select new { t2.BAR };
int result = 0;
foreach (var record in q2}
{
result = record.BAR.Value;
}
Any help or guidance would be appreciated, Thanks!
I think this should work:
var query = from item in db.T
where item.FOO == 555
group item by item.BAR into g
select new { Bar = g.Key, Max = g.Max(x => x.FOO_INDEX) };
So basically you're taking the same approach as in the SQL: group the data, then take the key for the group and the maximum FOO_INDEX within the group.
You can group elements in LINQ to Entities the same way you do in SQL. The syntax would look something like:
var q = from t in db.T
where t.FOO == 555
group t by t.BAR into g
select new {
Bar = group.Key,
Max = g.Max(b => b.FOO_INDEX)
};

Categories