Paging results

Hello!

I know Aurelius can do paging by using Take and Skip, but I can't find in the manual any way to return the whole count which we need for the UI. The manual says that using Take(0) will return an empty result so my question is: how do I make sure to have all the meta-information (total count, etc.) to send to the client?

Cheers!

You have to do it yourself, by writing a query that returns the count number. As a reference, here is how XData does it for a generic TCriteria:

    if (QueryInfo.InlineCount = TQueryInlineCount.AllPages) or ResourceInfo.IsCount then
    begin
      CriteriaCount := Criteria.Clone;
      try
        CriteriaCount.AutoDestroy := False;
        CriteriaCount.Take(-1);
        CriteriaCount.Skip(0);
        CriteriaCount.OrderItems.Clear;
        CriteriaCount.SetProjections(TProjections.Sql<Int64>('Count(*)'));
        CountResult := CriteriaCount.UniqueValue;
        try
          EntityCount := CountResult.Values[0];
        finally
          CountResult.Free;
        end;
      finally
        CriteriaCount.Free;
      end;  
    end

Hi!

Okay so this is what I am doing currently:

var
  ResultData: TVisiteDynResult;
  ORM: TObjectList<TSSTPERSONALE_VISITE>;
  ORMVisita: TSSTPERSONALE_VISITE;
  CountResult: TCriteria;

Then in the code:

if start  = 0  then
      begin
        CountResult := ObjectManager.Find<TSSTPERSONALE_VISITE>.Select(TProjections.Sql<Int64>('Count(*)')).Clone;
        CountResult.AutoDestroy := False;
        ResultData.total_count := CountResult.UniqueValue.Values[0];
      end;

And then releasing it in my finally. Unfortunately, I am still having memory leaks, so I am certain something isn't quite right. The remainder works as intended so the problem is here, in how I get and use the count.

Any ideas?

Thanks!

The Clone is just needed if you are using the original criteria for the query itself. If you don't, then you don't need neither Clone or AutoDestroy. Just do this:

var 
  CountResult: TCriteriaResult;
  CountResult := ObjectManager
    .Find<TSSTPERSONALE_VISITE>
    .Select(TProjections.Sql<Int64>('Count(*)'));
    .UniqueValue;
  try
    ResultData.total_count := CountResult.Values[0];
  finally
    CountResult.Free;
  end;

Hi!

Yes, I want both the count and the list, for I am doing paging and I may need both :smiley:
Your suggestion obviously worked for intended purpose. but alas I need to be able to do both the count and the list with the same criteria :stuck_out_tongue:

Can you please help?

Thanks!

That's exactly my first solution with Clone, if I understand right what you mean by "with the same criteria".

Hi, yes, that's exactly what I mean but my code does not do what I suppose it should do, so I am still stuck.

What am I getting wrong? I'll want that kind of structure all over the place, eventually.

That would be more or less like this:

var 
  Criteria: TCriteria;
  CriteriaCount: TCriteria;
begin
  Criteria := Manager.Find<TYourClass>.<build_your_criteria_here>;
  try
      Criteria.AutoDestroy := False;
      CriteriaCount := Criteria.Clone;
      try
        CriteriaCount.AutoDestroy := False;
        CriteriaCount.Take(-1);
        CriteriaCount.Skip(0);
        CriteriaCount.OrderItems.Clear;
        CriteriaCount.SetProjections(TProjections.Sql<Int64>('Count(*)'));
        CountResult := CriteriaCount.UniqueValue;
        try
          EntityCount := CountResult.Values[0];
        finally
          CountResult.Free;
        end;
      finally
        CriteriaCount.Free;
      end;  
    end;
  // Now execute your original criteria normally
  MyData := Criteria.List;
finally
  Criteria.Free;
end;

I've just come across this and it sounds like what I need to implement but I haven't a clue where to put it.

Please help an old man :grinning:

:slight_smile:
Well, you should copy, paste and adapt to your needs. I can't tell you where to put it, because I don't know what you want to do with it? What is your need, exactly?