Sort in LINQ based on certain order - linq

I have the following records:
ID Type TypeID
1 BHD 2
2 BHD 2
3 AUY 4
4 CDL 5
5 BUL 6
6 ZUL 7
What I like to do is to sort it so it is sorted by following where AUY, BHD and CDL are sorted alphatically and BUL and ZUL are appended at the end.
AUY
BHD
CDL
BUL
ZUL
How can this be done in Linq. Note that I have TypeID that I am sorting by.
I have a foreach as such:
foreach (var types in ent.OrderBy(s => s.TypeID)

You can always sort in multiple steps:
foreach(var types in ent
.OrderBy(s => s.Type == "BUL" || s.Type == "ZUL" ? 1 : 0)
.ThenBy(s => s.Type))
{
// Do your thing here...
}

Related

Unable to check if a list of int is completely contained in another int list

I have a list of int that represents service ids. and I want to make sure that all of those ids exist in the database.
In other words , I want to scan the list of ids and the table of services to make sure that all of these ids exist in the database.
I tried this :
List<int> ids;//[1,52]
var x = _context.Services.Any(s => ids.Contains(s.Id));//service ids = [1,2,3]
but it returned True , which is not the desired output.
I've also tried it this way :
_context.Services.Any(s => ids.Any(id => id == s.Id)!=null);
and this way
_context.Services.Any(s => ids.Any(id => id == s.Id)!=null);
with no luck as well. what is the right way to do it? I'm using EFCore 3.1.8
Normally you would use Queryable.Except for this.
If you have two sequence of items, and you do A except B, then if you have nothing left, then apparently every item from A is also an item in B.
IEnumerable<int> requiredIds = ...
IQueryable<int> serviceIds = dbContext.Services.Select(service => service.Id);
bool someRequiredIdsMissing = requiredIds.Except(serviceIds).Any();
Alas, your A is local and your B is in the database. So I guess this won't work.
What you can do, is to keep only Service Ids that are in the list of required Ids, and count them. If there are less, then apparently some requiredIds are not in serviceIds.
var requiredServiceIds = serviceIds.Where(serviceId => requiredIds.Contains(serviceId);
bool allRequiredAvailale = requiredServiceIds.Count() != requiredIds.Count();
Example:
IEnumerable<int> requiredIds = new [] {1, 2, 7, 20};
Total: 4 elements
Your service Ids are: 1 2 4 5 8 20 25
requiredServiceIds : 1 2 20: total 3 elements
So allRequiredAvailale is false;
Example 2:
Your service Ids are: 1 2 4 5 7 8 20 25
requiredServiceIds : 1 2 7 20: total 4 elements
So allRequiredAvailale is true;

Laravel/Eloquent whereIn/where with a pair of sets

I have 3 tables in my database.
The first two tables are just normal tables with an ID and some other columns like:
Table 1
ID
col01
1
...
2
...
Table 2
ID
col01
1
...
2
...
The third table is some kind of a relation/assignment table:
Table 3
ID
table1_id
table2_id
text
1
1
1
..
2
1
2
..
3
1
3
..
4
2
1
..
5
3
3
..
Now I do have a SQL statement which does exactly what I want:
SELECT * FROM table_3 where (table1_id, table2_id) in ( (1, 1), (2, 1), (3, 3));
So Im sending following Request Body to the API:
{
"assignments": [
{
"table1_id": 1,
"table2_id": 1
},
{
"table1_id": 2,
"table2_id": 1
},
{
"table1_id": 3,
"table2_id": 3
}
]
}
I do validate my the request with
->validate($request,
[
'assignments' => 'required|array',
'assignments.*.table1_id' => 'required|integer|min:1|max:20',
'assignments.*.table2_id' => 'required|integer|min:1|max:20'
]
Now Im kinda stuck how to use the eloquent commands (e.g. whereIn) to get my desired output.
Thanks in advance!
EDIT
So I took the workaround of arcanedev-maroc mentioned here: https://github.com/laravel/ideas/issues/1021
and edited it to fit my Request.
Works like a charm.
Laravel does not provide any functions by default. The core team said that they would not maintain this feature. You can read the post here.
But you can create your own query to accomplish this. I am providing a function that you can use as per your specification:
public function test(Request $request)
{
$body=$request->input('data');
$data=json_decode($body)->assignments;
$query='(table1_id, table2_id) in (';
$param=array();
foreach($data as $datum)
{
$query=$query."(".$datum->table1_id.",".$datum->table2_id."), ";
}
$query = rtrim($query, ", ");
$query = $query.")";
$result=DB::table('table3')->whereRaw($query)->get();
return $result;
}
So I took the workaround of arcanedev-maroc mentioned here: https://github.com/laravel/ideas/issues/1021
and edited it to fit my Request.
Works like a charm.

Group by and Count result in LinQ

I have 1 very basic table which I need to query in order to get the amount (count) of rooms in each building code using a LinQ query.
So far i have this:
var myQuery =
from s in Locations
group s.Room by s.BldgCode into t
select t.Count();
myQuery.Dump();
with this output
Query (3 items)
2
4
7
How can I include the Building code details so I have an output like this:
BldgCode NoRooms (3 items)
A 2
B 4
C 7
foreach(var line in data.GroupBy(info => info.Room )
.Select(group => new {
BldgCode = group.Key,
NoRooms = group.Count()
})
{
Console.WriteLine("{0} {1}", line.BldgCode , line.NoRooms );
}

LINQ - writing a query with distinct and orderby

I'm quite new to LINQ.
Suppose that I had the following table:
Incident
ID DeviceID Time Info
1 1 5/2/2009 d
2 2 5/3/2009 c
3 2 5/4/2009 b
4 1 5/5/2009 a
In LINQ, how could I write a query that finds the most recent and distinct (on Device ID) set of incidents? The result I'd like is this:
ID DeviceID Time Info
3 2 5/4/2009 b
4 1 5/5/2009 a
Do you have to create an IEqualityComparer to do this?
You can get the most recent incidents for each device (this is how I understood your question) with:
var query =
incidents.GroupBy(incident => incident.DeviceID)
.Select(g => g.OrderByDescending(incident => incident.Time).First())
.OrderBy(i => i.Time); // only add if you need results sorted
int filterDeviceID = 10;
var incidents = (from incident in incidentlist
where incident.DeviceID == filterDeviceID
select incident).Distinct().OrderBy( x => x.Time);

LINQ query operator for log table

I am trying to find the corerct LINQ to SQL query operator and predicate combo that can operate on an audit table.
Imagine a table called Setting that has three columns : rowID, DefID, and Value.
I want to be able to check that every DefID ( in this case all definition 1 through 3 ) has at least one row which has a value set to true.
the LINQ expression should return a bool true or false. For example,
RowID DefID Value
1 1 true
2 2 false
3 3 true
LINQ returns false because DefID = 2 does not have any value = true
RowID DefID Value
1 1 true
2 2 false
3 2 true
returns false because defid 3 is missing
RowID DefID Value
1 1 true
2 1 false
3 2 true
4 3 true
returns true because ALL definitions have at least one value = true
Here is an example using extension methods:
int[] ids = new int[] { 1, 2, 3 };
bool allFound = Settings.Where( s => s.Value && ids.Contains( s.DefID ) )
.Select( s => s.DefID )
.Distinct()
.Count() == ids.Length;
I've never used linq to sql, but the linq to objects would look something like this:
defIds.All(d => d.rows.Any( row => row.Value == true ) )
To do it in raw SQL, I don't think it's possible in one query. You could do something like this though:
select id from DefIds
join rows on row.DefId = DefIds.ID
where row.Value = true
That would give you a list of defId's which have true values. In code you could then do something like
DefIds.Select(d => d.id).ToArray() == (results from select).ToArray()
Well, there are a lot of valid ways to do this. One simple way is:
int[] DefIDs = new int[] {1, 2, 3};
bool bHasValidDefs =
(
from set in myDataBase.settings
where
set.Value == true
&& DefIDs.Contains(set.DefID)
select set.DefID
).Distinct().Count() == DefIDs.Count();
This gets the number of unique DefIDs that are in your valid list and also have at least one "value == true" row. It then makes sure that the number of these valid DefIDs is equal to the expected value that you define above.
If you are ok with having a ValidSettings or SettingsMaster table, you could:
bool allFound = myContext.SettingsMaster.All(m=> m.Settings.Any(s=>s.Value));
For the current tables version, I would
int[] allIds = new int[] {1, 2, 3};
var validIds = (
from s in myContext.Settings
where s.Value
select s.DefId
)
.Distinct().ToList();
bool allFound = allIds.All(id => validIds.Contains(id));

Resources