LINQ checking if an ICollection<int> has any crossover with c# array - c#

So i have a c# array that contains integers.
In my database i have an entity called request. Request has a one to many relationship with a table called Weeks. In weeks there is a requestID and a week (so week 1 would have value 1, week 2 -> 2 etc.).
I need to construct a where clause that if the database record has any sort of overlap with my c# array, it gets that record.
So for instance, say a request has weeks 1,2,3 connected to it in the database, and my c# array has [3,5,6], i want that request to be pulled.
Any ideas of how to get this done?
this is my current LINQ code so far
IQueryable<request> proposedRequest = db.requests.Include(r => r.rooms);
proposedRequest = proposedRequest.Where(r=>r.booked.Equals(1));
proposedRequest = proposedRequest.Where(r => r.roundID.Equals(roundID));
proposedRequest = proposedRequest.Where(r=>r.day.Equals(day));
proposedRequest = proposedRequest.Where(s=>s.start<time+length && s.start + s.length > time);
//I attempted something here but obviously it doesnt work
proposedRequest = proposedRequest.Where(r=>weeks.Contains(r.weeks_request.Any(f=>f.week)));
so in my request table there is a attribute weeks. This is either 1 or 0. If it is 1, this means the request is for a standard set of weeks, which is 1-12. This means that there is not an entry in the weeks_request table for this request.
If the weeks attribute is 0, this means that it is any permutation of weeks 1-16, not not the standard 1-12. Therefore there is an individual entry in the weeks_request table for each week selected.
The array weeks contains the weeks that the user wants to book for. But obviously they cannot book a week if it is already booked. Therefore, i need to find if it is already booked.
Any ideas?

Try changing:
r=>weeks.Contains(r.weeks_request.Any(f=>f.week))
To:
r=>r.weeks_request.Any(f=>weeks.Contains(f.week))
Update based on updated question
I am not entirely sure I follow what you have going on but try this query:
IQueryable<request> proposedRequest =
db.requests.Include(r => r.rooms)
.Where(r =>
r.booked.Equals(1) &&
r.roundID.Equals(roundID) &&
r.day.Equals(day) &&
r.start < time + length &&
r.start + r.length > time &&
((r.week == 0 && weeks.Any(w => w <= 12)
|| (r.week == 1 && r.weeks_request.Any(w => weeks.Contains(w.week));

Related

Getting first free Id from DB

Very often my code is returned on code review by other colleagues. I need explanation why second code is better than first.
Point is to get first empty Device Type Id from database in range predefined.
Device Type Ids can be:[1,2,4,10,11,12,14]
So if a range is from 10 to 20 predefined I want to get 13 because its first free Id.
So here is first code that do what it should:
firstFreeId = Enumerable.Range(_idRangeFrom.Value + 1, _idRangeTo.Value).First(i => !_dbContext.DeviceTypes.Any(dt => dt.DeviceTypeId == i));
Where _idRangeFrom and _idRangeTo are predefined ranges and _dbContext.DeviceTypes is a EF db Context that is a context of DB table DeviceTypes
Second code is:
var deviceTypeIds = _dbContext.DeviceTypes.Where(e => e.DeviceTypeId > _idRangeFrom.Value && e.DeviceTypeId < _idRangeTo.Value).Select(e => e.DeviceTypeId);
firstFreeId = Enumerable.Range(_idRangeFrom.Value + 1, _idRangeTo.Value).First(i => !deviceTypeIds.Any(dtId => dtId == i));
So my question is what I'm exactly getting with second code that I dont have in first?

Using C# Entity Framework find a value based on 2 high low column values

If the input value is between MinIncome and MaxIncome in my database table, I want to find the Amount db field value. So for instance if an input was 1525 falling between 1500 & 1599, I would expect a return value of 75.
How do I write a Linq or Lambda statement for this? Please see screen shot.
int income = 1525;
int amount = dbContext
.MyDbSet // use DbSet Property here
.Single(x => x.MinIncome < income && x.MaxIncome > income)
.Amount;
This selects the only element where the condition is met, and returns the amount of that object.
You could also use .Where(x => x.MinIncome < income && x.MaxIncome > income).Single().Amount to achieve the exact same result.
Other options include .SingleOrDefault() which prevents errors in case no entry in your DbSet matches, .First() which prevents errors if multiple entries match, or .FirstOrDefault() if no entries or multiple entries can match.
Try this:
var result = await DbContext
.Table
.Where(x => x.MinIncome <= value && value <= x.MaxIncome)
.Select(x => x.Amount).FirstOrDefaultAsync();

Using Linq to look for gap in dates

I have a single queryable that is ordered by id and then by date in descending order (most recent will appear first), tracking when the item (id) was online. If a gap is detected (more than 1 day) I want to filter out all of the dates that come prior to the gap, as to only get the most recent range of online days.
Currently I am looping through with for loops, however the data set is very large so I would like to improve performance using linq.
Are there any ways to compare the records by id, then date, and remove elements of that id after a gap is detected ( current.date - next.date != 1)?
Id
Date
1
2022/01/01
1
2021/12/31
1
2021/12/25
2
2021/12/20
2
2021/12/19
2
2021/12/18
2
2021/12/15
would return:
Id
Date
1
2022/01/01
1
2021/12/31
2
2021/12/20
2
2021/12/19
2
2021/12/18
var result = queryable
.GroupBy(entry => entry.Id)
.AsEnumerable()
.Select(entryGroup => entryGroup
.OrderByDescending(entry => entry.Date)
.Aggregate((EntryGroup: new List<Entry>(), GapDetected: false), (accumulated, current) =>
{
if (accumulated.GapDetected) return accumulated;
var previous = accumulated.EntryGroup.LastOrDefault();
if (previous == null || (previous.Date - current.Date).Days < 2) accumulated.EntryGroup.Add(current);
else accumulated.GapDetected = true;
return accumulated;
}))
.SelectMany(entryGroup => entryGroup.EntryGroup)
.ToList();
Note that only the GroupBy portion of the code is actually executed as an SQL query and the rest of the query is done locally since it can not be translated to SQL. I couldn't come up with a solution where the entire query could be translated to SQL but I wanted to show how this can be done with LinQ.

Entity Framework returns 0 results in spite of the data in the tables when `DbFunctions.DiffDays(DateTime.Now, c.ModifiedDate)` is used in the query

The below code should return the result from the table which has status = 1 and the data is older than 90 days. In the table there are a lot of data which has modified date more than90 days.
But this code is returning 0 results.
The datetime difference throws error so used DbFunctions instead since EF I am using is EF6.
IEnumerable<IncentiveClaim> claims = repository.Table
.Where(c => c.Status == 1
&& DbFunctions.DiffDays(DateTime.Now, c.ModifiedDate) >= 90)
.AsEnumerable();
The method has parameter as DbFunctions.DiffDays(smallestDateTime, LargestDateTime). So, the ModifiedDate should be first parameter and DateTime.Now should be second parameter. Then, you have to call .Value on the method to get the no. of days.
Modify the code as below:
IEnumerable<IncentiveClaim> claims = repository.Table
.Where(c => c.Status == 1
&& DbFunctions.DiffDays(c.ModifiedDate, DateTime.Now).Value >=
90)
.ToList();

Identifying Date Clashes using linq

I am looking to identify rows using linq where there is a date clash. I have (for this example) 5 columns
ID ref_id ref_Name Borrow_Date Return_Date
1 1343 Gate 13/09/2011 20/09/2011
2 1352 Door 20/09/2011 22/09/2011
3 1343 Gate 17/09/2011 21/09/2011
In this case my 'Gate' is clashing because someone wants to borrow it when someone else also wants to borrow it.
Is there anyway to identify the date range clashes using linq easily?
One way would be like this. It might be more performant variants out there though:
var collisions = myList.Where( d1 => !myList.Where( d => d != d1).All( d2 => d1.Return_Date <= d2.Borrow_Date|| d1.Borrow_Date >= d2.Return_Date));
This will return all rows that overlap with at least one other row. In the case above it will return all three of them, since the line with ID 3 overlaps both 1 and 2. If you change 1 to have Return_Date 17/09/2011, it will return only 2 and 3.
If you have a list of objects with properties as shown in your table, you can find out the books with the same title that have conflicting dates using something like this:
(Haven't tested this code, so there might be some typo bugs.)
var collisions = collection
.Join(collection, x => x.ref_Name, y => y.ref_Name,
(x, y) => new {
ID_x = x.ID,
ID_y = y.ID,
ref_id = x.ref_id,
ref_Name = x.ref_Name,
Borrow_Date_x = x.Borrow_Date,
Borrow_Date_y = y.Borrow_Date,
Return_Date_x = x.Return_Date,
Return_Date_y = y.Return_Date
}
)
.Where( z => (z.Return_Date_x > z.Borrow_Date_y && z.Borrow_Date_x < z.Return_Date_y))
.Where( z => z.ID_x != z.ID_y);
You will probably get duplicates of results. (i.e. ID 1 and 3, and ID 3 and 1)
Although it is certainly possible to identify these clashes in the database once they have occurred, would it not be a better to prevent the second person from borrowing an item when it is already scheduled to be borrowed. In this case this would be a simple matter of testing to ensure no existing rows with a ref_id of 1343 have a return date equal to or greater then the new requested borrow date.

Categories