Hibernate select query: only want to know existence [duplicate] - performance

This question already has an answer here:
HQL Query to check whether table has data or not
(1 answer)
Closed 7 years ago.
I need only the existence information of a record. I don't need the actual count. If there is a row (record) respect to the "where" condition, I will know that it exists.
If I write
select count(m) from MyEntity m where m.someProperty=1
it will count all the records and if there are many records, it may take long time and it will give me the information which I don't need actually.
How do I get the existence of a records with Hibernate HQL?

I found this one as best for me:
public Boolean existsOrNot (DTOAny i) {
Query q = getSession().
createQuery("select 1 from DTOAny t where t.key = :key");
q.setString("key", i.getKey() );
return (q.uniqueResult() != null);
}
from:
HQL Query to check whether table has data or not

Related

Getting max value on server (Entity Framework)

I'm using EF Core but I'm not really an expert with it, especially when it comes to details like querying tables in a performant manner...
So what I try to do is simply get the max-value of one column from a table with filtered data.
What I have so far is this:
protected override void ReadExistingDBEntry()
{
using Model.ResultContext db = new();
// Filter Tabledata to the Rows relevant to us. the whole Table may contain 0 rows or millions of them
IQueryable<Measurement> dbMeasuringsExisting = db.Measurements
.Where(meas => meas.MeasuringInstanceGuid == Globals.MeasProgInstance.Guid
&& meas.MachineId == DBMatchingItem.Id);
if (dbMeasuringsExisting.Any())
{
// the max value we're interested in. Still dbMeasuringsExisting could contain millions of rows
iMaxMessID = dbMeasuringsExisting.Max(meas => meas.MessID);
}
}
The equivalent SQL to what I want would be something like this.
select max(MessID)
from Measurement
where MeasuringInstanceGuid = Globals.MeasProgInstance.Guid
and MachineId = DBMatchingItem.Id;
While the above code works (it returns the correct value), I think it has a performance issue when the database table is getting larger, because the max filtering is done at the client-side after all rows are transferred, or am I wrong here?
How to do it better? I want the database server to filter my data. Of course I don't want any SQL script ;-)
This can be addressed by typing the return as nullable so that you do not get a returned error and then applying a default value for the int. Alternatively, you can just assign it to a nullable int. Note, the assumption here of an integer return type of the ID. The same principal would apply to a Guid as well.
int MaxMessID = dbMeasuringsExisting.Max(p => (int?)p.MessID) ?? 0;
There is no need for the Any() statement as that causes an additional trip to the database which is not desirable in this case.

Entity Framework Core: Database operation expected to affect 1 row(s) but actually affected 0 row(s) [duplicate]

This question already has answers here:
Unable to edit db entries using EFCore, EntityState.Modified: "Database operation expected to affect 1 row(s) but actually affected 0 row(s)."
(17 answers)
Closed 2 years ago.
I am using Sql Server on Linux with EC Core (2.1.0-preview1-final)
I am trying to update some data coming from a web Api service (PUT) request. The data (ticket) is passed correctly and gets deserialised into an object (ticket).
When I try to update, I use the following code:
public Ticket UpdateTicket(Ticket ticket)
{
using (var ctx = new SupportTicketContext(_connectionString))
{
ctx.Entry(ticket).State = EntityState.Modified;
ctx.SaveChanges(); // <== **BLOWS UP HERE**
var result = ctx.Tickets
.First(t => t.TicketId == ticket.TicketId);
return result;
}
}
The code throws the following error:
Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data
may have been modified or deleted since entities were loaded
I am able to Insert and fetch from the database, no problem.
If I restart Visual Studio, the error occurs usually on the second time I try to update ANY ticket (i.e. any other ticketId - it seems to be on the second and subsequent requests).
The updates are unpredictably successful! Sometimes I can update another ticket and it goes through (even on the 3rd or susequent request)
I have tried a number of modifications to the code, including
ctx.Attach(ticket);
but this does not help.
How do I get it to update the database successfully?
Any ideas on how to debug this? Logging seems to be difficult to set up.
Any ideas greatly appreciated.
There were two errors. First, I tried to call the Update() method without specifying a DbSet:
_applicationDbContext.Update(user);
Correct way:
_applicationDbContext.Users.Update(user);
The second error was trying to update a model that without first pulling it from the database:
public bool UpdateUser(IdentityUser model)
{
_applicationDbContext.Users.Update(model);
_applicationDbContext.SaveChanges();
return true;
}
Nope.
I first needed to retrieve it from the database, then update it:
public bool UpdateUser(IdentityUser model)
{
var user = _applicationDbContext.Users.FirstOrDefault(u => u.Id == model.Id);
user.PhoneNumberConfirmed = model.PhoneNumberConfirmed;
_applicationDbContext.Users.Update(user);
_applicationDbContext.SaveChanges();
return true;
}
Had such problem too, but the reason was a trigger I was using.
Changed the trigger type from "INSTEAD OF INSERT" to "AFTER INSERT" and instead of modifying and inserting the data I was allowing my command to insert the data to the table and then updated it using the trigger.

How to get a SOQL query out of a for loop

Code added.
I have searched endlessly for a solution here and cannot find one, please help!
I have three objects (A, B, and C). A has a lookup to B, and B is the master to C (detail). Both A and C have many records related to each B record.
I want to have a job run that gets a subset of records from object C (it will usually be around 5,000 records). Then go through each of those and get the records on Object A that lookup to the same Object B record, summarize an Object A number field, and put that on the C record.
I have successfully gotten this to work in small scale, <100 Object C records. But each Object C record requires a new SOQL query since I am iterating through them in a for loop after I get all the Object C records. Plus I know this it is not best practice to ever have a query in a loop.
How can I get this to work? Since the records share the relationship with Object B, is there another way to get the data from the Object A records that match? Or is there some way to pull two lists, one Object C and one Object A. Then summarize the Object A records and line the lists up some how?
Thanks in advance!
Code:
public class nightlyJob {
public static void updateNumbers(){
integer I = 29;
List<ObjectC__c> CUpdateList = new List<ObjectC__c>();
List<ObjectC__c> CpullList =
[SELECT ID, Index__c, ObjectB__r.id
FROM ObjectC__c
WHERE Index__c = :I];
for(ObjectC__c s : CpullList){
List<ObjectA__c> AList =
[SELECT ObjectB__c, Number__c
FROM ObjectA__c
WHERE ObjectB__c = :s.ObjectB__r.Id];
decimal NumSum = 0;
for(ObjectA__c a : AList){
NumSum = a.Number__c + NumSum;
}
s.Num__c = NumSum;
CUpdateList.add(s);
}
update CUpdateList;
}
}
It looks like you are really missing several fundamental concepts at the moment.
The biggest problem you are up against in SFDC development is that "database" operations are very expensive and are strictly limited. It's not just a matter of "best practice": if in a single transaction you exceed these limits -- number of SOQL calls, number of records returned, number of records updated, number of DML statements, etc. -- your transaction will fail. For details, search online for "Salesforce Execution Governors and Limits".
You can write code that works within these limitations, but there is a bit of a learning curve.
First, learn to use collections with SOQL queries to get your SOQL queries out of loops. This is a.k.a. "bulkfication" and it fundamental to SFDC development:
List<ObjectC__c> CpullList =
[SELECT ID, Index__c, ObjectB__r.id
FROM ObjectC__c
WHERE Index__c = :I];
// Create a map with the results of this query.
// key=ObjectC__c.Id, value = Object__c record
Map<Id, ObjectC__c> objCmap = Map<Id, ObjectC__c>(CpullList);
// Build a set of all the Object_B id's from this result set
Set<Id> objBids = new Set<Id>();
for (ObjectC__c record : CpullList) {
objBids.add(record.ObjectB__r.id);
}
// Now you can use only one SOQL query instead of a loop
List<ObjectA> AList = [SELECT ObjectB__c, Number__c
FROM ObjectA__c
WHERE ObjectB__c in:objBids];
Next, use "SOQL aggregate functions" whenever you can. Example: in your code here, you could use "SUM()" and "group by" instead of performing these calculations with loops:
// Get the sum of ObjectA__c.Number__c for each Object B in objBIds
AggregateResult[] groupedResults = [select ObjectB__c,
sum(Number__c) sumA
from ObjectA__c
where ObjectB__c in: objBids
group by ObjectB__c];
for (AggregateResult ar : groupedResults) {
System.debug('Object B Id' + ar.get('Objectb__c'));
System.debug('Sum of ObjectA__c.Number__c' + ar.get('sumA'));
// Here, you might want to build a Map<Id, Integer> sumAmap:
// key=Object B ID, value=sumA
// and then use it along with objCmap to build a collection of Object C's
// for your update statement...
}
You can continue this process and apply these ideas to make the code more efficient.
But even after you have your methods working as efficiently as possible, you still may run into limits due to the number of records you're dealing with. At that point, you will need to learn about the Batchable interface, the Queuable interface and #future calls (how to process a larger number of records, split across transactions) That's really too much to information to cover in a single SO answer.

Dynamic Linq Select

I am having trouble wrapping my head around the Dynamic LinQ select. I have read Scott Gu's blog and each of the suggested posts but still cannot get my little brain to understand. I need to query an entity object passing in a variable for the column name. Assume an entity (table) containing 3 columns named: Mon, Tue & Wed. These contain data for each record. I do not know the column to hit at compile time so I need to pass a column name into the query. How can I accomplish this either using DLink or directly using Expression Trees?
Don't need Dynamic LINQ for that...
var columniwant="Mon"; // Or "Tue" or "Wed"
var query=db.stuff here;
IQueryable<string> result;
switch(columniwant)
{
case "Mon": result=query.Select(q=>q.Mon); break;
case "Tue": result=query.Select(q=>q.Tue); break;
case "Wed": result=query.Select(q=>q.Wed); break;
}
That said, I would think this would work:
var result=db.stuff here.Select(columniwant);

mondodb linq query fails - is it mongodb driver or linq

Admittedly I don't perform lots of LINQ queries. Therefore I'm uncertain whether the problem I see is due to an obvious LINQ blunder or a legitimate Mongo driver problem (I use 10Gen 1.9.2 C# driver). In the below code I get an error indicating invalid where clause for .where(ques => unAnswered...). Code compiles fine but generates runtime error stating "unsupported where clause". Am I up against a driver limitation or is my LINQ bad?
public IEnumerable<QuestionDataModel> getUnanswered(String username, Category cat)
{
IQueryable<QuestionDataModel> questions =
from e in this.questionCollection.AsQueryable<QuestionDataModel>()
where (e.questionCategory == cat)
select e;
IQueryable<AnswerDataModel> answers =
from e in this.answerCollection.AsQueryable<AnswerDataModel>()
where (e.questionCategory == cat && e.username == username)
select e;
IEnumerable<QuestionDataModel> filteredquestionslist = null;
if (answers.Count()==0) // it's possible the user has not answered anything
filteredquestionslist = questions.ToList();
else
filteredquestionslist = questions.Where(ques => unAnswered(ques, ref answers)).ToList();
return filteredquestionslist;
}
private bool unAnswered(QuestionDataModel qdm, ref IQueryable<AnswerDataModel> answer_queryable)
{
bool retval;
retval = answer_queryable.Any(ans => ans.questionID == qdm.questionID) ? false:true;
return retval;
}
You can't combine two collections in a single query like this with MongoDB - there are no join operations in the database. (You also generally can't use your own method like that in LINQ since they don't translate into SQL (or any other database) but that's a separate issue and even if you fixed that it still wouldn't help here. unAnswered question cannot be translated into Mongo a query).
You must either iterate over one collection, performing the other query and yield return the results you want (i.e. the join happens not in the database but on the computer making the query), or you could denormalize the data in some way such that you can query a single collection to get the results. Of if the number of questions is really small you could possibly load them into a list using .ToList() and then operating on that list in memory.

Resources