Skip to main content
Solved

Showing API response in Grid


I want to show a book mark history notes fetch from API call in customer screen (AR303000)

I added the below grid 

<px:PXButton runat="server" ID="btnBookMarkHistory" Text="Book Mark History"><AutoCallBack Command="BookMarkHistory" Target="ds" /></px:PXButton>
 <px:PXGrid ID="PXGrid2" runat="server" DataSourceID="ds">
     <Levels>
         <px:PXGridLevel DataMember="BookMarkHistoryView">
             <Mode AllowAddNew="False" AllowDelete="False" AllowUpdate="False" />
             <Columns>
                 <px:PXGridColumn DataField="Type" TextAlign="Left" />
                 <px:PXGridColumn DataField="ShortNotes" TextAlign="Left" />
             </Columns>
         </px:PXGridLevel>
     </Levels>
 </px:PXGrid>

And my DAC is

 [Serializable]
 [PXCacheName("BookMarkHistory")]
 public class BookMarkHistory : PXBqlTable, IBqlTable
 {
     #region Type
     [PXString(10, IsUnicode = true)]
     [PXUIField(DisplayName = "Type")]
     public virtual string Type { get; set; }
     public abstract class type : PX.Data.BQL.BqlString.Field<type> { }
     #endregion

     #region ShortNotes
     [PXString(500, IsUnicode = true)]
     [PXUIField(DisplayName = "Short Notes")]
     public virtual string ShortNotes { get; set; }
     public abstract class shortNotes : PX.Data.BQL.BqlString.Field<shortNotes> { }
     #endregion

 }

my graph is

public class CustomerMaintExt : PXGraphExtension<CustomerMaint>
{
 public PXFilter<BookMarkHistory> BookMarkHistoryView;
 public PXAction<Customer> BookMarkHistory;
 [PXButton]
 [PXUIField(DisplayName = "BookMark History")]
 protected virtual IEnumerable bookMarkHistory(PXAdapter adapter)
 {
     BLBookmarkhistory bLBookmarkhistory = new BLBookmarkhistory();
     List<BookMarkHistory> lstResult = bLBookmarkhistory.getBookmarkHistory();
     if (lstResult.Count > 0)
     {
         BookMarkHistoryView.Cache.Clear();
         foreach (var result in lstResult)
         {
             BookMarkHistoryView.Cache.Insert(result);
         }
     }
     return adapter.Get();
 }
}

The problem is there should have 5 rows in the grid but it shows only one data. The first data only .I have debugged my code and found  foreach (var result in lstResult) this loops 5 times and the correct data is in insert BookMarkHistoryView.Cache.Insert(result); But still only first data in the Grid .
Why and how to solve ? any help would be appreciated

Best answer by PraveenBeo

Thank you everyone for your time .

My intention was to use 

[PXVirtualDAC]
public PXSelect<BookMarkHistory> BookMarkHistoryView;

Without accessing database table . But unfortunately it dons not work for me. So finally I created a database table that fit my API response and used PXSelect without [PXVirtualDAC] . Now my issue solved . But don't know what was the issue with [PXVirtualDAC] even though we use  [PXVirtualDAC] , Shows Error:  Incorrect syntax near the keyword 'OPTION'. .  

 

Thank you 

View original
Did this topic help you find an answer to your question?

16 replies

Forum|alt.badge.img+1

Hello. I think you need to mark at least one of your DAC fields as IsKey. 
Assuming that region is the key field in the database, then I think the following should work.  

 

     #region Type
     [PXString(10, IsUnicode = true, IsKey = true)]
     [PXUIField(DisplayName = "Type")]
     public virtual string Type { get; set; }
     public abstract class type : PX.Data.BQL.BqlString.Field<type> { }
     #endregion


  • Author
  • Freshman II
  • 8 replies
  • March 4, 2025

@stephenward03  Thank you for your fast response . Actually there is no database table for the DAC . I just want to show the API response in the grid . No need for persist the data . And no key also . Thank you


Forum|alt.badge.img+1

Still worth trying out the IsKey idea, even if the data isn’t going to a database table, the cache will need to know about key fields so that inserts, updates and deletes can be performed correctly. 


  • Author
  • Freshman II
  • 8 replies
  • March 4, 2025

@stephenward03  Thank you for your time. When I put IsKey = true , It start showing the last data only. Previously it was showing the first one only . But still only one row in Grid . Thank you 


  • Author
  • Freshman II
  • 8 replies
  • March 4, 2025

Is it because I am using PXFilter ? Was not able to use PXSelect as it try to fetch data from database table and I don't have one . Is that the issue how can I select non persisting multiple record ?


Forum|alt.badge.img+6
  • Captain II
  • 550 replies
  • March 4, 2025

I think it’s because you’re returning adapter.Get()

I have a similar chunk of code to collect ARSalesPrice records and show them in a grid. At the end of my IEnumerable code I have this instead of adapter.Get()

TPSalesPricesView.Cache.IsDirty = false;

foreach (var priceRec in TPSalesPricesView.Cache.Cached)
{
  yield return priceRec as TPSalesPriceDAC;
}

This way the method returns the records I’ve stuffed into my cache.

So I think yours will look like this at the end, once you’ve collected the records:

BookMarkHistoryView.Cache.IsDirty = false;

foreach (var bookmarkRec in  BookmarkHistoryView.Cache.Cached)
{
  yield return bookmarkRec as BookMarkHistory;
}

 


  • Author
  • Freshman II
  • 8 replies
  • March 5, 2025

@Django  It also don’t work for me . I think it is because of the PXFilter  I use . PXFilter  return only one record .To get multiple record , If I use PXSelect , it tries to query from database and goes error as I don't have such table in database and it is only a non persist API response . Is there any way to get multiple record without fetch from database can be used instead of PXSelect ?. Thank you for your time .


Forum|alt.badge.img+1

I think the attribute PXVirtualDAC is what you need. See the following article.

On-The-Fly Data Transformation using Virtual Data Access Class – Acumatica Developers Blog

 


  • Author
  • Freshman II
  • 8 replies
  • March 6, 2025

@stephenward03  Yes . I have tried that . In my Graph CustomerMaintExt , I changed  public PXFilter<BookMarkHistory> BookMarkHistoryView; to

 [PXVirtualDAC]
 public PXSelect<BookMarkHistory> BookMarkHistoryView;

But still it shows -> Error:  Incorrect syntax near the keyword 'OPTION'. Hope [PXVirtualDAC] is not working as expected . Is there any other ways or did something wrong . Thank you very much for your time 


Forum|alt.badge.img+6
  • Captain II
  • 550 replies
  • March 6, 2025

I use PXFilter for my table as well. The documentation says not to use a DAC with a key defined but I used a blog entry from ​@Yuriy Zaletskyy that showed how to build up a cache (I can’t find it now, maybe Yuriy can link it). It’s very similar to the blog entry that ​@stephenward03 posted.

In my virtual DAC I have a PXInt field with IsKey=true. I just populate it with the value from an int variable that I increment in my loop.

PXFilter is supposed to work on only a single record but by introducing the integer primary key field it appears to be able to cache multiple records. (24R2)

    [PXVirtualDAC]
    public PXFilter<TPSalesPriceDAC> TPSalesPricesView;

Hmmm….

I think I figured it out what it might be - here is the code I use to populate my cache:

          int linenumber = 0;
          foreach (ARSalesPrice priceRec in existingPricing)
          {
            TPSalesPriceDAC salesPrice = new TPSalesPriceDAC();
            ARSalesPriceExt priceRecExt = priceRec.GetExtension<ARSalesPriceExt>();
            linenumber++;
            salesPrice.LineNbr = linenumber;
            salesPrice.TPPriceType = priceRec.PriceType;
            salesPrice.TPBreakQty = priceRec.BreakQty;
            salesPrice.TPPrice = priceRec.SalesPrice;
            salesPrice.TPExpiresOn = priceRec.ExpirationDate;
            salesPrice.TPMarkupPercentage = priceRecExt.UsrMarkupPercentage;
            salesPrice.TPPriceCode = priceRec.CustPriceClassID;
            TPSalesPricesView.Insert(salesPrice);
          }

          TPSalesPricesView.Cache.IsDirty = false;

          foreach (var priceRec in TPSalesPricesView.Cache.Cached)
          {
            yield return priceRec as TPSalesPriceDAC;
          }

What I noticed in my code that you’re not doing is that I’m creating a record in the cache with new. Then I populate the DAC with the fields from my source, then I call .Insert to put it in the cache.

Then I set .IsDirty to false so nothing will try to save to the database. Finally, I yield return all of the records in the cache.


  • Author
  • Freshman II
  • 8 replies
  • March 6, 2025

@Django  Thank you very much for your time and effort . But unfortunately it did not work for me .

public class CustomerMaintExt : PXGraphExtension<CustomerMaint>
{

 [PXVirtualDAC]
 public PXFilter<BookMarkHistory> BookMarkHistoryView;
 public PXAction<Customer> BookMarkHistory;
 [PXButton]
 [PXUIField(DisplayName = "BookMark History")]
 protected virtual IEnumerable bookMarkHistory(PXAdapter adapter)
 {
     BLBookmarkhistory bLBookmarkhistory = new BLBookmarkhistory();
     List<BookMarkHistory> lstResult = bLBookmarkhistory.getBookmarkHistory();
     if (lstResult.Count > 0)
     {
         BookMarkHistoryView.Cache.Clear();
         foreach (var result in lstResult)
         {
             BookMarkHistory bookMarkHistory = new BookMarkHistory();
         bookMarkHistory.Type = result.Type;
         bookMarkHistory.ShortNotes = result.ShortNotes;
             BookMarkHistoryView.Cache.Insert(result);
         }
     }
     BookMarkHistoryView.Cache.IsDirty = false;
     return adapter.Get();
     
  }
}

I have changed my code like this . Still only one record is shown .
I cannot use

foreach (BookMarkHistory bookmarkRec in BookMarkHistoryView.Cache.Cached)
        {
            yield return bookmarkRec;
        }

because the button return type is  type 'PX.Objects.AR.Customer'.

Thank you


Forum|alt.badge.img+6
  • Captain II
  • 550 replies
  • March 6, 2025

What are the requirements for this process. For mine, the user presses the action button and then I’m showing a smart panel with a grid. I’m populating the grid with records from the ARSalesPrice table plus some other records.

So, in my case, my PXFilter view:

    [PXVirtualDAC]
    public PXFilter<TPSalesPriceDAC> TPSalesPricesView;

Is calling the code to populate the records of the view (see below). You have your Action button populating the cache. I think you want the view to populate itself how I’ve done it (not in the PXAction code). Then, change your PXAction button code to call the view like a normal view and handle the records however you want. Any code that forces your view to read records will run the public IEnumerable code (see below). If you need the records refreshed, make a call to  BookMarkHistoryView.Cache.Clear(); and the next time your view is called, if you use the design pattern from the blog, it will re-populate.

  public IEnumerable tPSalesPricesView()
  {
    bool found = false;

    foreach (var priceRec in TPSalesPricesView.Cache.Cached)
    {
    found = true;
    yield return priceRec as TPSalesPriceDAC;
    }

    if (!found)
    {
    TPSalesPricesView.Cache.Clear();

    SOLine soLine = Base.Transactions.Current;
    SOOrder soOrder = Base.Document.Current;
    Location loc = Base.location.Current;

    if (soLine != null)
    {

      var existingPricing = SelectFrom<ARSalesPrice>
       .LeftJoin<InventoryItem>.On<InventoryItem.inventoryID.IsEqual<ARSalesPrice.inventoryID>>
       .Where<InventoryItem.inventoryID.IsEqual<@P.AsInt>
         .And<
          ARSalesPrice.priceType.IsEqual<PriceTypes.customerPriceClass> 
           .Or<
           ARSalesPrice.priceType.IsEqual<PriceTypes.customer>.And<ARSalesPrice.customerID.IsEqual<@P.AsInt>>
           >
         >
         .And<ARSalesPrice.siteID.IsEqual<@P.AsInt>>
         .And<
         ARSalesPrice.effectiveDate.IsLessEqual<@P.AsDateTime>.Or<ARSalesPrice.effectiveDate.IsNull>
           .And<
           ARSalesPrice.expirationDate.IsGreaterEqual<@P.AsDateTime>.Or<ARSalesPrice.expirationDate.IsNull>
           >
        >
      >
       .OrderBy<Asc<ARSalesPrice.inventoryCD,
         Asc<ARSalesPrice.priceType,
         Asc<ARSalesPrice.uOM,
         Asc<ARSalesPrice.breakQty,
         Asc<ARSalesPrice.effectiveDate>>>>>>
       .View.Select(Base, soLine.InventoryID, soOrder.CustomerID, soLine.SiteID, soOrder.OrderDate, soOrder.OrderDate);

      int linenumber = 0;
      foreach (ARSalesPrice priceRec in existingPricing)
      {
      TPSalesPriceDAC salesPrice = new TPSalesPriceDAC();
      ARSalesPriceExt priceRecExt = priceRec.GetExtension<ARSalesPriceExt>();
      linenumber++;
      salesPrice.LineNbr = linenumber;
      salesPrice.TPPriceType = priceRec.PriceType;
      salesPrice.TPBreakQty = priceRec.BreakQty;
      salesPrice.TPPrice = priceRec.SalesPrice;
      salesPrice.TPExpiresOn = priceRec.ExpirationDate;
      salesPrice.TPMarkupPercentage = priceRecExt.UsrMarkupPercentage;
      salesPrice.TPPriceCode = priceRec.CustPriceClassID;
      TPSalesPricesView.Insert(salesPrice);
      }

      TPSalesPricesView.Cache.IsDirty = false;

      foreach (var priceRec in TPSalesPricesView.Cache.Cached)
      {
      yield return priceRec as TPSalesPriceDAC;
      }
    }

    }
  }

 


Yuriy Zaletskyy
Jr Varsity I
Forum|alt.badge.img+3

Items with PXFilter are purposed for single record, not for more then one record. That’s why IsKey doesn’t make sense.

Below goes a screenshot from metadata of PXView:

 


Forum|alt.badge.img+6
  • Captain II
  • 550 replies
  • March 6, 2025

I totally agree that PXFilter is designed to work with one record. And I’m not saying my way is the correct way. But it works - PXFilter will allow itself to be ‘stuffed’ with more than one record.

I pulled my logic from piecing together a bunch of posts include this one:

Again, to be clear, this was me getting this functionality to finally work after multiple attempts at it. So once it worked, I moved on to the next item on my to do list. :)


Yuriy Zaletskyy
Jr Varsity I
Forum|alt.badge.img+3

I admit and admire your creativity by all means! Just want to share personal approach, not to fight with Acumatica framework, as in the long run, you may have issues with maintenance, upgrades, and tricky bugs. 

 


  • Author
  • Freshman II
  • 8 replies
  • Answer
  • March 10, 2025

Thank you everyone for your time .

My intention was to use 

[PXVirtualDAC]
public PXSelect<BookMarkHistory> BookMarkHistoryView;

Without accessing database table . But unfortunately it dons not work for me. So finally I created a database table that fit my API response and used PXSelect without [PXVirtualDAC] . Now my issue solved . But don't know what was the issue with [PXVirtualDAC] even though we use  [PXVirtualDAC] , Shows Error:  Incorrect syntax near the keyword 'OPTION'. .  

 

Thank you 


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings