Announcement

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

    My weird requirement

    Ok, I will try to explain what I am trying to do since some time ago and the problems I had.

    I have in my application two concepts: persons and contracts. A person can have many contracts.

    I have a big listGrid which shows a certain view over all contracts. This listGrid is rather complex, so the listGridView.ds.xml has some important criteria which define the SQL being generated (using if/else in velocity). The tableClause
    is also rather complex (with a lot of left joins), but I think this is not relevant here, since I am not using $criteria values there, only in the whereClause.

    listGridView.ds.xml

    Code:
    ....
    <operationBinding operationType="fetch" >
    			<tableClause>
    				
    				(select * from
    				v_vertraege_gemeinsame_einrichtungen
    				union
    				select * from
    				v_vertraege_normale_einrichtungen) as alle_vertraege
    
    				join t_person
    				on t_person.f_person_id = alle_vertraege.person_id
    				
    				left join t_laender as staatsangehoerigkeit_laender
    				on staatsangehoerigkeit_laender.f_iso_kuerzel = t_person.f_staatsangehoerigkeit1
    				
    				left join t_einrichtungen as einrichtungen
    				on
    				einrichtungen.f_id = alle_vertraege.einrichtung_id
    				
    				left join
    				t_geschwister as geschwister
    				on
    				geschwister.f_person_id =
    				t_person.f_person_id
    				
    				left join
    				t_adressen as adressen
    				on
    				adressen.f_id = t_person.f_adresse
    
    				left join
    				t_tex_texte as tGeschlecht
    				on
    				tGeschlecht.f_id = t_person.f_geschlecht
    
    				left join
    				t_tex_texte as tReligion
    				on
    				tReligion.f_id = t_person.f_religion		
    
    				left join ......................................................
    				
    			</tableClause>
    
    			<whereClause>
    				'1' = '1'
    				
    					AND
    					( --Begin: die ganze WhereClause
    					(
    					alle_vertraege.einrichtung_id in
    	
    					(select f_id from t_einrichtungen as
    					t_e
    					where 
    					
    					#if($criteria.kategorieId)
    					t_e.f_kategorie =
    					$criteria.kategorieId
    					#else
    					1=1
    					#end
    	
    					#if($criteria.bezeichnungId )
    					--Evaluiert nur wenn bezeichnungId ist angegeben
    					and t_e.f_bezeichnung =
    					$criteria.bezeichnungId
    					#end
    
    					....................................
    	
    					)
    	
    					) --End: die ganze Where Clause
    					
    				
    				#if($criteria.shouldShow )
    				AND f_should_show =
    				$criteria.shouldShow
    				#end
    				
    				AND 
    				
    				alle_vertraege.vertrag_typ IN ('NORMAL','GEMEINSAME_EINRICHTUNG')
    
    				
    				AND ($defaultWhereClause)
    				
    			</whereClause>
    		</operationBinding>
    When I fetch the listGrid, I set the criteria depending for example which menu the user clicked, etc.

    So we have a listgrid, for example:

    id, person_id, contract_id, person_name, contract_title
    1, 1, 1, john, a
    2, 1, 2, john, b
    3, 1, 3, john, c
    4, 2, 4, marc, d

    So we have 3 contracts (with contract_id = 1,2,3 which belong to person=1 (john) and one contract with contract_id=4 which belong to person=2 (marc) and the listGrid shows this.

    It is important to note that we have many more persons/contracts!! The records shown depend on the <whereClause>, more specifically on the $criteria variables passed in.

    The user can then double click on one record on the listGrid, and a dynamic form opens. There, a lot of additional information is shown. This information can either be edited directly in the form or using some buttons.

    The form uses a separate datasource: form.ds.xml, which is also quite different that the listGrid. This form is divided into tabs. In the first tab the personal information of the person can be edited. A new tab
    is opened for each contract the user wants. For example:
    Double click on 1,1,1,john,a:

    Form opens. Its first tab contains personal information of john. The second tab contains contract information from contract a. The user can also decide to open more contracts from this person, for example b. A new tab
    opens for each contract edited.

    So the form is divided into valuesManagers. One for the personal information, one for each contract. The personal information is saved using the form.ds.xml datasource, and the contract tabs use a contract.ds.xml datasource.

    When the user finishes editing the form, he presses the "save" button of the form. It then saves all changes to the database.

    Since the listGrid and the form both use different datasources, the listGrid does not get actualized, for example when john's name is changed to johny. This is whan I want to do! I want to actualize the listGrid after the form edits.

    So if we change the name "john" to "johny", I need to actualize the first three records of the listgrid.
    We can also change something regarding only one contract, so if we change "a" to "z", then only the first record should be actualized.

    But it is very important that ONLY THE CORRECT records regarding the whereClause are shown after the listGrid actualization.
    So if we have a boolean field "shouldShow", and we have in the whereClause the following: "... and shouldShow=true", only records with shouldShow=true should be shown after the actualization.

    So I had three approaches:

    1) I just called invalidateCache() and reloaded the complete listgrid. This is the only approach which works well, but it is very slow, since everything must be loaded again. But this can be optimized, since we only edit 1 or 2 or 3 records, and we know which records we actualized.
    For example: we want to actualize all records for user=1, since his name changed. So I tried 2 other approaches. I think to call invalidateCache() only for actualizing 1 - 2 -3 records is not very nice.

    2) I tried to use updateCaches() (refer to http://forums.smartclient.com/showthread.php?t=28084 )
    But I had problems with my listGrid.ds.xml because of the <whereClause>. You said:

    "updateCaches() applies only client-side filtering to determine whether a record should be added to a grid. That's all the information it has, since SQL fragments are, by design, never exposed to the browser (this would be information leakage from a security perspective)."

    So, in our case, the <whereClause> is not taken into account. So, in our example, records with "shouldShow=false" are also shown after the actualization, although we have a whereClause which says: "... and shouldShow=true". So the user asks himself why is he seeing records with shouldSee=false! And the user gets very confused. This is not nice.

    3) I tried to use addRelatedUpdate(): Refer to http://forums.smartclient.com/showthread.php?t=28441
    But I also had problems with my listGrid.ds.xml because of the <whereClause>. You said:

    "The ListGrid is by design totally unaware of the customized SQL in your operationBinding. It will show or not show records based on the criteria you've applied client-side. See the ResultSet documentation for more information about automatic cache synchronization."

    So the user also sees records with shouldShow=false, and the user gets confused. This is not nice.

    You also said:
    "You need to return to your previous code that got the updates as a separate fetch and make calls to updateCaches() if you need to fulfill this requirement."

    But this is my 2) approach? Refer to 2) for the problems there.

    So what is the correct approach here?
    I hope I made clear what is the problem, if not, just ask :-)

    I am actually almost happy with the addRelatedUpdate() (approach 3). It works almost well, and very fast. Just the issue with the <whereClause> is the problem.

    As you see, I have tried a lot regarding this problem, but no good solution found. Do you really think this is a weird requirement?

    I just want to update a listGrid based on a form's changes.
    I would need some method "actualizeListGrid(int personId)", which fetches the record and shows it only if it should be shown (regarding the actual whereClause).

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

    #2
    I created a testcase which shows the problem. Please take look at it.

    TestingModule
    Code:
    public class TestingModule implements EntryPoint {
    
    	public void onModuleLoad() {
    
    		final ListGrid personListGrid = new ListGrid();
    		personListGrid.setWidth(500);
    		personListGrid.setDataSource(DataSource.get("personListGrid"));
    		personListGrid.setAutoFetchData(false);
    
    		ListGridField personId = new ListGridField("person_id", "ID");
    		ListGridField personName = new ListGridField("person_name", "Name");
    		ListGridField categoryText = new ListGridField("category_text", "Category text");
    
    		personListGrid.setFields(personId, personName, categoryText);
    		personListGrid.setAutoFitData(Autofit.VERTICAL);
    		personListGrid.setAutoFitMaxRecords(10);
    		
    		IButton showAButton = new IButton("Show category A");
    		showAButton.setWidth(300);
    		showAButton.addClickHandler(new ClickHandler() {
    			
    			@Override
    			public void onClick(ClickEvent event) {
    				Criteria c= new Criteria();
    				c.addCriteria("categoryText", "A");
    				personListGrid.fetchData(c);
    			}
    		});
    		
    		IButton showBButton = new IButton("Show category B");
    		showBButton.setWidth(300);
    		showBButton.addClickHandler(new ClickHandler() {
    			
    			@Override
    			public void onClick(ClickEvent event) {
    				Criteria c= new Criteria();
    				c.addCriteria("categoryText", "B");
    				personListGrid.fetchData(c);
    			}
    		});
    		
    		IButton showAllButton = new IButton("Show all categories");
    		showAllButton.setWidth(300);
    		showAllButton.addClickHandler(new ClickHandler() {
    			
    			@Override
    			public void onClick(ClickEvent event) {
    				personListGrid.fetchData();
    			}
    		});
    		
    		IButton changeAnnaCategory = new IButton("Change anna category A->B");
    		changeAnnaCategory.setWidth(300);
    		changeAnnaCategory.addClickHandler(new ClickHandler() {
    			
    			@Override
    			public void onClick(ClickEvent event) {
    				/* Change Anna's category from A to B. */
    				Record updateRec = new Record();
    				updateRec.setAttribute("person_id", 3);
    				updateRec.setAttribute("category_id", 2);
    				DataSource.get("personForm").updateData(updateRec);
    			}
    		});
    		
    		
    		VLayout layout = new VLayout(15);
    		layout.setHeight(300);
    		layout.addMember(showAButton);
    		layout.addMember(showBButton);
    		layout.addMember(showAllButton);
    		layout.addMember(personListGrid);
    		layout.addMember(changeAnnaCategory);
    
    		layout.draw();
    	}
    
    }
    personListGrid
    Code:
    <DataSource  
            ID="personListGrid"  
            tableName="person"  
            serverType="sql"  
        >  
            <fields>  
                <field name="person_id" type="integer" primaryKey="true" />  
                <field name="person_name" type="text"  />  
                <field name="category_id" type="integer" customSQLExpression="person.category_id" />
                <field name="category_text" type="text" customSQLExpression="categories.category_text" />
            </fields>  
            
            
            <operationBindings>
    
    		<operationBinding operationType="fetch" >
    		
    			<tableClause>
    			person left join categories on categories.category_id = person.category_id
    			</tableClause>
    			<whereClause>
    			
    			categories.category_id in
    			(select cat.category_id from categories as cat where
    			1=1
    			
    			#if($criteria.categoryText)
    			AND cat.category_text=$criteria.categoryText
    			#end
    			
    			)
    			
    			AND
    				 
    			($defaultWhereClause)
    			
    			</whereClause>
    		</operationBinding>
    		
    		<operationBinding operationType="fetch" operationId="fetch_simple" >
    			<tableClause>
    			person left join categories on categories.category_id = person.category_id
    			</tableClause>
    			<whereClause>
    			 
    			($defaultWhereClause)
    			
    			</whereClause>
    		</operationBinding>
    		</operationBindings>
              
        </DataSource>
    personForm
    Code:
    <DataSource  
            ID="personForm"  
            tableName="person"  
            serverType="sql"  
        >  
            <fields>  
                <field name="person_id" type="integer" primaryKey="true" />  
                <field name="person_name" type="text"  />  
                <field name="category_id" type="integer" />
            </fields>  
            
            <operationBindings>
            
            	<operationBinding operationType="update">
    				<serverObject className="zedes2.server.dmi.TestDMIHandler"
    					methodName="doUpdate" />
    			</operationBinding>
    		
    		</operationBindings>
            
        </DataSource>
    TestDMIHandler
    Code:
    public class TestDMIHandler {
    
    	public DSResponse doUpdate(DSRequest dsRequest,
    			HttpServletRequest servletRequest) throws Exception {
    
    		DSResponse response = dsRequest.execute();
    
    		Integer personId = (Integer) response.getRecord().get("person_id");
    		DSRequest newRequest = new DSRequest("personListGrid",
    				DataSource.OP_FETCH);
    		newRequest.setOperationId("fetch_simple");
    
    		newRequest.setCriteria("person_id", personId);
    		newRequest.setRPCManager(dsRequest.getRPCManager());
    		DSResponse fetchResponse = newRequest.execute();
    		fetchResponse.setOperationType(DataSource.OP_UPDATE);
    
    		response.addRelatedUpdate(fetchResponse);
    
    		return response;
    
    	}
    
    }
    So basically we have two tables:
    person and categories. Let them have this content:

    person
    Code:
    person_id, person_name, category_id
    1, john, 1
    2, marc, 2
    3, anna, 1
    categories
    Code:
    category_id, category_text
    1, A
    2, B
    You have 3 Buttons in the form:
    "Show category A", "Show category B", "Show category C".

    When you click on the respective button, you see the people with this category. In my application I have similar parameters, and depending on the button clicked, parameters are set in a similar way.

    So please click on "Show category A". You see people with category A: john and anna. This is correct.

    Then I have a button "Change anna category A->B", which changes anna's category from A to B. This is a simulation of my complex form. That is why I use another datasource for this.
    When the button is pressed, the change happens correctly, and the DB is updated correctly. The record in the listGrid is also updated: you see the new category from anna.

    BUT: this record shouldn't be visible anymore!! Since we pressed the button "Show category A", we should only see the people with category A!. Anna does not have this category any more!

    So how to update the grid accordingly?

    I hope with this testcase my use case is clearer.

    It would be great for the listGrid to reevaluate its current criteria (with a fetch for example) when it gets the result from addRelatedUpdate(), so it shows the received record only when it applies.

    As I explained in my first post, the only solution until now is calling listGrid. invalidateCache() to load ALL records again with the current criteria. But this isn't nice and very slow, only for just a small update.
    Last edited by edulid; 31 Oct 2013, 03:41.

    Comment


      #3
      Note for anyone finding this thread: this issue was solved in this thread.

      Comment

      Working...
      X