I have a method called getAllEmployees() which returns a pageable.
Lets say the page size is 1 and started with page 0
Pageable pageable = PageRequest.of(0, 1);
Page<String> allEmployees = service.getAllEmployeeNames(pageable)
while(true) {
for(String name: allEmployees.getContent()) {
// check whether the employee needs to be deleted or not based on certain conditions
boolean isDelete = service.checkEmployeeToBeDeleted()
if (isDelete)
EmployeeEntity entity = service.findByName(name);
service.delete(entity);
}
if (!page.hasNext()) {
break;
}
pageable = page.nextPageable();
}
In this scenario, all employees are not deleted only those matching the condition will be
deleted
as page size is 1
Let's say, total 6 employees
emp pageable(pageNumber, pageSize)
1 (0 ,1)
2 (1 ,1)
3 (2 ,1)
4 (3 ,1)
5 (4 ,1)
6 (5 ,1)
when 1 gets deleted the pageable will be like
2 (0 ,1)
3 (1 ,1)
4 (2 ,1)
5 (3 ,1)
6 (4 ,1)
but as we go with page.nextPageable() the next one will be like (1,1)
So on next fetch, it will pick emp 3, and emp 2 will be missed
I had a similiar problem. The problem is that you are doing the 'search' and the 'deletion' in one step while you are on an iteration. So the deleting will modify the search, but you are one step further with you initial search. (I think this is the main problem).
My solutin was, first search ALL objects that need to be deleted and put them into a list. And after the searching, delete those objects. So your code could be something like:
Page<String> allEmployees = service.getAllEmployeeNames(pageable)
List<EmployeeEntity> deleteList = new ArrayList<>();
while(true) {
for(String name: allEmployees.getContent()) {
// check whether the employee needs to be deleted or not based on certain conditions
boolean isDelete = service.checkEmployeeToBeDeleted()
if (isDelete)
EmployeeEntity entity = service.findByName(name);
deleteList.add(entity);
}
if (!page.hasNext()) {
// here iterate over delete list and service.delete(entity);
break;
}
pageable = page.nextPageable();
}
You need only use nextPageable() when you not delete employee. Just add conditions like this:
if (!isDelete) {
pageable = page.nextPageable();
}
Related
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;
This pertains to my previous query.
I am able to get batches of records from ActiveRecord using the following query:
Client.offset(15 * iteration).first(15)
I'm running into an issue whereby a user inputs a new record.
Say there are 100 records, and batches are of 15.
The first 6 iterations (90 records) and the last iteration (10 records) works. However, if a new entry comes in (making it a total of 101 records), the program fails as it will either:
a) If the iteration counter is set to increment, it will query for records beyond the range of 101, resulting in nothing being returned.
b) If the iteration counter is modified to increment only when an entire batch of 15 items are complete, then repeat the last 14 items plus 1 new item.
How do i go about getting newly posted records?
dart code:
_getData() async {
if (!isPerformingRequest) {
setState(() {
isPerformingRequest = true;
});
//_var represents the iteration counter - 0, 1, 2 ...
//fh is a helper method returning records in List<String>
List<String> newEntries = await fh.feed(_var);
//Count number of returned records.
newEntries.forEach((i) => _count++);
if (newEntries.isEmpty) {
..
}
} else {
//if number of records is 10, increment _var to go to the next batch of 10.
if(_count == 10) {
_var++;
_count = 0;
}
//but if count is not 10, stay with the same batch (but previously counted/display records will be shown again)
}
setState(() {
items.addAll(newEntries);
isPerformingRequest = false;
});
}
}
In my code logic, firstly i am deleting large records with multiple queries & then doing bulk insert.
Here is the Code :-
using (var scope = new TransactionScope())
{
using (var ctx = new ApplicationDbContext(schemaName))
{
// Delete
foreach (var item in queries)
{
// Delete queries - more than 30 - optimized already
ctx.Database.ExecuteSqlCommand(item);
}
// Bulk Insert
BulkInsert(ConnectionString, "Entry", "Entry", bulkTOEntry);
BulkInsert(ConnectionString, "WrongEntry", "WrongEntry", bulkWrongEntry);
}
scope.Complete();
}
The problem here is in the delete part. The delete queries are taking around 10 minutes. This results in the locking of the records, so this is holding the other users from fetching or manipulating records.
I have my code in the TransactionScope as if there is any error while deleting then it will roll back the whole transaction.
I have tried to delete the records in chunks through stored procedures, but that didn't helped here as there is still lock on the records due to the TransactionScope.
How to prevent locks on the records?
Sample of Delete Queries :-
DELETE FROM [Entry]
WHERE CompanyId = 1
AND EmployeeId IN (3, 4, 6, 7, 14, 17, 20, 21, 22,....100 more)
AND Entry_Date = '2016-12-01'
AND Entry_Method = 'I'
if you need to delete the employees in chunk you can split the list of employee with this
public static List<IEnumerable<T>> Partition<T>(this IEnumerable<T> source, int length)
{
var count = source.Count();
var numberOfPartitions = count / length + ( count % length > 0 ? 1 : 0);
List<IEnumerable<T>> result= new List<IEnumerable<T>>();
for (int i = 0; i < numberOfPartitions; i++)
{
result.Add(source.Skip(length*i).Take(length));
}
return result;
}
you can use this method to split the list to small chunks and delete them one chunk at a time so other user can use the table between chunks
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 );
}
This question already has answers here:
LINQ and pagination [duplicate]
(3 answers)
Closed 9 years ago.
I need to apply paging logic to this Query. How can i do that?
My query is as follows,
myresultset = from req in myreqTable
join streq in myStreqTable on req.ID.ToString() equals new SPFieldLookupValue( Convert.ToString( streq[FormID] ) ).LookupValue
where (filter(req) && filter1(streq))
join plnts in plantDetails on Convert.ToString( streq[RequestID) equals Convert.ToString(plnts[RequestID]) into mySet
from s in mySet.DefaultIfEmpty()
select new Mytable() {
FormID = Convert.ToString(streq[FormID]),
RequestID = Convert.ToString(streq[RequestID])
};
Add .Skip( pageSize * pageIndex ).Take( pageSize ); to the end of your query. Note that pageIndex is zero-based (so the first page is 0, the second page is 1 and so on).
However your Linq doesn't look valid to me, and has some syntax errors. Are you sure this is your code as it is in your editor?
recordsForCurrentPage = myresultset.Skip( recordsPerPage * pageNumber ).Take( recordsPerPage )
This is assuming that your page number starts with 0. Otherwise subtract 1 from pageNumber.
Use Take and Skip methods:
myresults = myresults.Skip((page - 1) * pageSize).Take(pageSize);
I assumed page numeration starts from 1.