Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Problem with addRelatedUpdates()

    I want to refresh a listgrid using addRelatedUpdates(), as you recommend me here:

    http://forums.smartclient.com/showthread.php?t=28084

    In the "general case", this works well. The second listgrid refreshes correctly after I update the first one.

    But in the following scenario, the second listgrid is not being updated.

    TestingModule
    Code:
    public class TestingModule implements EntryPoint {
    
    	public void onModuleLoad() {
    
    		final ListGrid countryList = new ListGrid();
    		countryList.setWidth(500);
    		countryList.setAlternateRecordStyles(true);
    		countryList.setDataSource(DataSource.get("worldDSExport"));
    		countryList.setAutoFetchData(true);
    
    		ListGridField pk = new ListGridField("pk");
    		pk.setHidden(true);
    		ListGridField countryName = new ListGridField("countryName", "Country");
    		ListGridField capital = new ListGridField("capital", "Capital");
    		ListGridField continent = new ListGridField("continent", "Continent");
    
    		countryList.setFields(pk, countryName, capital, continent);
    		countryList.setAutoFitData(Autofit.VERTICAL);
    		countryList.setShowFilterEditor(true);
    		countryList.setAutoFitMaxRecords(10);
    
    		VLayout layout = new VLayout(15);
    		layout.setHeight(300);
    
    		HLayout formLayout = new HLayout(15);
    
    		IButton addBtn = new IButton("Correct capital");
    		addBtn.addClickHandler(new ClickHandler() {
    
    			@Override
    			public void onClick(ClickEvent event) {
    				Record updateRecord = new Record();
    				updateRecord.setAttribute("pk", 3);
    				updateRecord.setAttribute("capital", "Washington");
    				DataSource.get("worldDSExport").updateData(updateRecord);
    
    			}
    		});
    		formLayout.addMember(addBtn);
    		layout.addMember(formLayout);
    
    		layout.addMember(countryList);
    
    		final ListGrid countryList2 = new ListGrid();
    		countryList2.setWidth(500);
    		countryList2.setAlternateRecordStyles(true);
    		countryList2.setDataSource(DataSource.get("worldDSExport2"));
    		countryList2.setAutoFetchData(false);
    
    		ListGridField pk2 = new ListGridField("pk");
    		pk2.setHidden(true);
    		ListGridField countryName2 = new ListGridField("countryName", "Country");
    		ListGridField capital2 = new ListGridField("capital", "Capital");
    		ListGridField continent2 = new ListGridField("continent", "Continent");
    
    		countryList2.setFields(pk2, countryName2, capital2, continent2);
    		countryList2.setAutoFitData(Autofit.VERTICAL);
    		countryList2.setShowFilterEditor(true);
    		countryList2.setAutoFitMaxRecords(10);
    		
    		Criteria c2Criteria = new Criteria();
    		c2Criteria.addCriteria("filterContinent", "true");
    
    		countryList2.fetchData(c2Criteria);
    
    		layout.addMember(countryList2);
    
    		layout.draw();
    	}
    
    }
    worldDSExport:
    Code:
    <DataSource  
            ID="worldDSExport"  
            tableName="worldDS"  
            serverType="sql"  
        >  
            <fields>  
                <field name="pk"            type="integer"    hidden="true"            primaryKey="true" />  
                <field name="countryCode"   type="text"                   required="true"   />  
                <field name="countryName"   type="text"                 required="true"   />  
                <field name="capital"       type="text"                 />  
                <field name="government"    type="text"              length="500"      />  
                <field name="continent"     type="text"              >  
                </field>  
                <field name="independence"  type="date"                 />  
                <field name="area"          type="float"       />  
                <field name="population"    type="integer"             />  
                <field name="gdp"           type="float"                  />  
                <field name="member_g8"     type="boolean"                      />  
            </fields>  
            
            
            <operationBindings>
            
            <operationBinding operationType="update">
    			<serverObject className="zedes2.server.dmi.TestDMIHandler"
    				methodName="doUpdate" />
    		</operationBinding>
            
            </operationBindings>
        </DataSource>
    worldDSExport2:
    Code:
    <DataSource  
            ID="worldDSExport2"  
            tableName="worldDS"  
            serverType="sql"  
        >  
            <fields>  
                <field name="pk"            type="integer"    hidden="true"            primaryKey="true" />  
                <field name="countryCode"   type="text"                   required="true"   />  
                <field name="countryName"   type="text"                 required="true"   />  
                <field name="capital"       type="text"                 />  
                <field name="government"    type="text"              length="500"      />  
                <field name="continent"     type="text"              >  
                </field>  
                <field name="independence"  type="date"                 />  
                <field name="area"          type="float"       />  
                <field name="population"    type="integer"             />  
                <field name="gdp"           type="float"                  />  
                <field name="member_g8"     type="boolean"                      />  
            </fields>  
            
            
            <operationBindings>
    
    		<operationBinding operationType="fetch" >
    			
    			<whereClause>
    			#if($criteria.filterContinent )
    			continent = 'Europe' and
    			#else
    			continent = 'Asia' and
    			#end
    			 
    			($defaultWhereClause)
    			
    			</whereClause>
    		</operationBinding>
    		</operationBindings>
              
        </DataSource>
    TestDMIHandler
    Code:
    public class TestDMIHandler {
    
    	public DSResponse doUpdate(DSRequest dsRequest,
    			HttpServletRequest servletRequest) throws Exception {
    
    		DSResponse response = dsRequest.execute();
    
    		Integer pk = (Integer) response.getRecord().get("pk");
    		DSRequest newListRequest = new DSRequest("worldDSExport2",
    				DataSource.OP_FETCH);
    
    		newListRequest.setCriteria("pk", pk);
    		newListRequest.setRPCManager(dsRequest.getRPCManager());
    		DSResponse fetchResponse = newListRequest.execute();
    		fetchResponse.setOperationType(DataSource.OP_UPDATE);
    
    		response.addRelatedUpdate(fetchResponse);
    
    		return response;
    
    	}
    
    }
    Note the operationBinding which is causing the problem (in worldDSExport2):

    Code:
    <operationBinding operationType="fetch" >
    			
    			<whereClause>
    			#if($criteria.filterContinent )
    			continent = 'Europe' and
    			#else
    			continent = 'Asia' and
    			#end
    			 
    			($defaultWhereClause)
    			
    			</whereClause>
    		</operationBinding>
    In my application I use criteria to control some SQL parts. In this particular case it doesn't make much sense, but in my application I use this, so I created this testcase based on it.

    At first, the listGrid is fetch with $criteria.filterContinent set, so "continent = 'Europe' and" is evaluating.

    But when updating using addRelatedUpdates(), this seems not to be the case, because the second part ("continent = 'Asia' and") is evaluating.

    But that is the whole point? I have a listgrid in my application which takes its records from table A. This listgrid has some criteria like $criteria.filterContinent.

    In another part, I update table A, so I need to update the listgrid. But of course, I need the listgrid to maintain its original criteria, I only want to update the record changed.

    What am I doing wrong? Why doesn't this work?

    I am using SmartGWT 4.0: v9.0p_2013-10-17/PowerEdition Deployment (built 2013-10-17)

    #2
    Hi edulid,

    please see http://forums.smartclient.com/showthread.php?t=28359 and this JavaDoc: http://www.smartclient.com/smartgwte....DSRequest%29"
    The provided DSResponse should have operationType "update", "add" or "remove" - there is no way for a "fetch" response to meaningfully update arbitrary caches. However, if you have a list of updated records (possibly retrieved via DataSource.fetchData) you can call updateCaches() multiple times with DSResponses of type "update" formed from the list of records retrieved via fetchData().
    Best regards,
    Blama

    Comment


      #3
      The response has a UPDATE type as you see from my code:

      Code:
      fetchResponse.setOperationType(DataSource.OP_UPDATE);

      Comment


        #4
        Please look in the server side logs and watch the used connections/transactions-numbers for the two requests.
        Most likely they will differ, at least they do that for me if I don't use the same RPCManager for the two requests inside a transaction.
        Code:
        DSRequest fetchRequest = new DSRequest(dataSource, DataSource.OP_FETCH, rpcManagerOf1stRequest)
        I'm also using a
        Code:
        SQLTransaction.startTransaction(dsRequest.getRPCManager());
        (with commitTransaction() + endTransaction()), but I'm not sure if this is necessary.

        Assuming that you are using Oracle (or any RDMBS with transaction support) what happens is the following IFF the two DSs refer to the same table.
        1) DMI starts
        2) 1st transaction updates
        3) 2nd transaction reads old value
        4) 1st request piggybacks old value
        5) 1st request is returned
        6) DMI ends and implicitly commits.
        7) new value is persisted, but client gets the old value from 3)

        You should be able to see that (if the scenario is as described) in the client console RPC tab as well.

        Best regards,
        Blama

        Comment


          #5
          As I said in my first post, the code actually works without the operationBinding. So that is not the problem. The problem is within the operationBinding.

          Comment


            #6
            The ListGrid criteria are on the client-side only.
            Most likely your $criteria.filterContinent is null for the TestDMIHandler's fetch-request(are they?) and the other where-condition is used, perhaps in combination with the 2nd PK-criteria from the TestDMIHandler, leading to a zero-row response (PK is for Washington, America ds.xml is for Europe/Asia).
            You can see the generated SQL or look in the client's console RPC tab what the piggybacked request returns.

            If that is true you could try the following:
            Create a 2nd fetch operation binding in ds.xml with another OperationId, and leave it as it is (so no <whereCondition>). Use that operationId in your TestDMIHandler's fetch-request.
            The client should now get a row and will display/update it's data according to it's (client-side) criteria.

            Just saw:
            You don't have client-side criteria for continent. Is there a reason you can't add them, perhaps in addition to your addCriteria("filterContinent", "true")?
            If so, why don't you set the TestDMIHandler's fetch-request criteria like in the client, so two criteria for PK and for Criteria("filterContinent", "true")?

            Otherwise, as Isomorphic always says, the server log really helps.

            Best regards,
            Blama

            Comment


              #7
              Originally posted by Blama View Post

              Just saw:
              You don't have client-side criteria for continent. Is there a reason you can't add them, perhaps in addition to your addCriteria("filterContinent", "true")?
              If so, why don't you set the TestDMIHandler's fetch-request criteria like in the client, so two criteria for PK and for Criteria("filterContinent", "true")?
              Because that is the whole point!
              I want to update a listGrid after updating a table, without having to know in the server all the criteria from the listGrid.

              So, of course, the $criteria.filterContinent is null for the TestDMIHandler's fetch-request. There we can't know the criteria the listGrid uses.

              Isomorphic, any ideas?
              Last edited by edulid; 29 Oct 2013, 09:18.

              Comment


                #8
                OK, understood.
                I assume you can't use criteria based on the current ListGrid/DS fieldnames?
                Can you add another Field to the DS and hidden to the ListGrid that evaluates to true (via a virtual column in the DB or a DS field with a customSelectExpression) for continent = 'Europe' and false for continent = 'Asia' and add criteria for that field?
                That way the LG knows if it should display the piggybacked rows from the fetch.

                If not I can't think of a suitable handover point for that use case.

                Best regards,
                Blama

                Comment


                  #9
                  Originally posted by Blama View Post
                  Can you add another Field to the DS and hidden to the ListGrid that evaluates to true (via a virtual column in the DB or a DS field with a customSelectExpression) for continent = 'Europe' and false for continent = 'Asia' and add criteria for that field?
                  That way the LG knows if it should display the piggybacked rows from the fetch.
                  No, since this is a very basic example of what I am trying to do. My application listgrid has more criteria, etc. This criteria comes from outside (from a click somewhere else in the application). So it is not possible to calculate the criteria based on the fields.

                  Comment


                    #10
                    OK, then I could only think of client side solutions.
                    Either with
                    1) queuing LG1.update + LG2.fetch on button click (see http://www.smartclient.com/smartgwte...ctions_queuing) or
                    2) with some addDataArrivedHandler on the 1st ListGrid.

                    For 1) I don't know how this behaves on the server side. This only works if the two requests are handled in the same transaction one after the other.
                    For 2) you'll have two round-trips as 2nd request is fired after the first completes.

                    Best regards,
                    Blama

                    Comment


                      #11
                      There's a lot of back and forth here, but it seem the problem is: "how do I insert a record into a ListGrid's cache no matter what filter criteria are applied to it?"

                      Obviously this cannot be done solely from the server side (where the criteria are not available). You will need to call getCriteria() on the ListGrid and call updateCaches() providing a record that matches the filter criteria of the ListGrid.

                      Comment

                      Working...
                      X