cslaDataSource and resusable namevaluelist

cslaDataSource and resusable namevaluelist

Old forum URL: forums.lhotka.net/forums/t/3472.aspx


jhoojharsinghyadav posted on Tuesday, September 04, 2007

Rocky ,

i am using cslaDatasource to bind with comboboxes in asp.net .
but i had done a little bit of modification in the namevalue list class for my bussiness objct .
like instead of making a namevalue list for each and everyobject , what i wish is i do create a criteria class which expects a parameter type for name value list and then based on criteria.type calls the underlying stored procedure to populate the csladatasource collectioin .

could  you throw somelight on how to achieve this .

thanks
govind

RockfordLhotka replied on Tuesday, September 04, 2007

I don't recommend doing this, as it makes your object model less intuitive. All name/value lists end up as the same type, which can be confusing.

However, you can certainly do this. I'd recommend using some sort of type-based factory model to get a "data provider" in the DP_F() method of your name/value class:

Private Overloads Sub DataPortal_Fetch(ByVal criteria As CustomCriteria)
  Dim dataProvider As IDataProvider = DataProvider.GetProvider(criteria.ListType)
  Using dataProvider
    Using dr As SqlDataReader = dataProvider.GetData()
      ' loop through data and populate list
    End Using
  End Using
End Sub

The GetProvider() method would create an instance of IDataProvider, which is defined as:

Public Interface IDataProvider
  Function GetData() As SqlDataReader
End Interface

The particular instance of IDataProvider would be based on the ListType - which could be some Type object, or a string descriptor or whatever you want to use to identify the particular name/value data to be returned.

jhoojharsinghyadav replied on Wednesday, September 05, 2007

Rocky,

Regarding to achieve this , here is what i had done .

 [Serializable()]
    public class FillCombo : NameValueListBase<int, string>
    {
        #region Business Methods

        public static int DefaultRole (string combotype)
        {
            FillCombo list = GetList(combotype);
            if (list.Count > 0)
                return list.Items[0].Key;
            else
                throw new NullReferenceException(
                  "No Data available; ");
        }

        #endregion

        #region Factory Methods

        private static FillCombo[] _list=new FillCombo[10];

      
        /// <summary>
        /// Returns a list of roles.
        /// </summary>
        public static FillCombo GetList(string combotype)
        {
            //here reading the IndexerList collection
            if (_list == null) //mean no collection exist
              return  _list [Convert.ToInt32(combotype)] =  DataPortal.Fetch<FillCombo>
                  (new FilteredCriteria(combotype));
          else if (_list[Convert.ToInt32(combotype)] == null) //mean its not null
            {
                return _list[Convert.ToInt32(combotype)] = DataPortal.Fetch<FillCombo>
                 (new FilteredCriteria(combotype));
            }
            else  //mean its already there
            {
                //get the collection by name and return it .

                return _list[Convert.ToInt32(combotype)];
            }
           
           
        }

    


        /// <summary>
        /// Clears the in-memory RoleList cache
        /// so the list of roles is reloaded on
        /// next request.
        /// </summary>
        public static void InvalidateCache()
        {
            _list = null;
        }

        public static void InvalidateCache(int Index)
        {
            _list[Index] = null;
        }
        private FillCombo()
        { /* require use of factory methods */ }

        #endregion

        #region Data Access
        [Serializable()]

             
        private new class Criteria
        { /* no criteria - retrieve all projects */ }

        [Serializable()]
        private class FilteredCriteria
        {
          
            private string _ComboType;
            public string ComboType
            {
                get { return _ComboType; }
            }

            public FilteredCriteria( string combotype)
            {
                _ComboType = combotype;
            }
        }

     
        private void DataPortal_Fetch(FilteredCriteria criteria)
        {
          
            this.RaiseListChangedEvents = false;
            using (SqlConnection cn = new SqlConnection(Database.DTCConnection))
            {
                
                cn.Open();
                using (SqlCommand cm = cn.CreateCommand())
                {
                    cm.CommandType = CommandType.StoredProcedure;
                    cm.CommandText =
CustomConstants.spFillCombos   ;
                    cm.Parameters.AddWithValue("@UserID", ((CustomProviders.CustomIdentity) Csla.ApplicationContext.User.Identity).Id    );
                    cm.Parameters.AddWithValue("@CodeType", Convert.ToInt32 (criteria.ComboType)  );
 
                   
                    using (SafeDataReader dr =
                      new SafeDataReader(cm.ExecuteReader()))
                    {
                        IsReadOnly = false;
                        //adding the default selection to the list
                        this.Add(new NameValuePair(0, "------Select------"));
                        while (dr.Read())
                        {
                            this.Add(new NameValuePair(
                              dr.GetInt32("id"), dr.GetString("name")));
                        }
                      
                        IsReadOnly = true;
                    }
                }
            }
            this.RaiseListChangedEvents = true;
        }

        #endregion
    }


but here i want a little bit of flexibility i.e i do not want to initially declare the size of the  _list instead it should be on the fly .the reason for this is with the current form of implementation it does support only upto 10 combotypes but that would not suffice mine requirement .

Could u suggest on same .



About the RBAC which i had talked to you a little while ago here is my implementation of the same ,

http://forums.lhotka.net/forums/thread/17224.aspx


Please give your comments on it .
Thanks
Govind

jhoojharsinghyadav replied on Saturday, September 22, 2007

Rocky ,

Problem is not with using a type based data provider or something like that .,but what the actual prob is that the private variable holding the name value collection is static i.e static _list
so if following that approach then no matter you choosse the dataprovider based factory or something the list will fill only once and on subsequent calls will return the old resultset ,
thats the issue .

thats is the reason i do had created an array of that private varialbe but still i m not to convieineit with that appproach as its not much logical and resourcefull for the reason i do may have as much as 50 types of name value list and being static array all would load in memory and consume resources .

not getting a better way out of it . can u suggest .

thanks
govind

RockfordLhotka replied on Saturday, September 22, 2007

Like I said, I don't think this is a good idea. NVLB streamlines the creation of a name/value list so the only real difference in each class is the DataPortal_Fetch(). Personally, I just create one NVL class for each list.

In any case, caching is a different issue. In the web, you can use System.Web.Caching, or you can use a static field, or you can use Application or you can use Session. These are all well-understood techniques for caching any sort of data in ASP.NET, and you should be able to find information about these options in any good ASP.NET book.

All of those options consume memory on the web server. That's the whole point of caching - you are consuming memory on the web server to avoid hitting the database over and over. If you can't spare the memory on the web server, then don't use caching and just reload the list from the database on each request.

jhoojharsinghyadav replied on Monday, September 24, 2007

Rocky,

I do honor your reply .
but again just to simplify my requirement it is like .
i do had created one nvl for each list .

now , i do not want them all to be called on by different names  mean say nvl for Country , City,FreightTerm ,PaymentTerm etc ....

i just simply want to call FilllCombos.GetList("Paymentterm")
and in its under the hood it do calls the corresponding NVL class .

just i want to achive it .

Secondly , like coming over to the listViewForms like as ProjectList.aspx , resourcelist.aspx in PTWeb,
i do have loads of list forms and they do have loads of columns etc . what i am trying to achive it is instead of doing the html coding required for boundcolumns , hyperlinkcolumns etc ... i require them to be achieved via a class .

i.e in my code i am gonna write on page load
if (!postback)
{
    GridViewTemplateSetting.setDevExgridview(dxGridviewList,Constants.CodeGrid);
    Applyauthorisationrule;
   
}

Class GridviewTemplateSetting
{
function setDevExgridview(DevexgridView dx,string GridType)
{
    case gridtype: CodeGrid
       Prepare Grid for code .
    case gridtype :CountryGrid
       Prepare Grid for Country
}
}

What my lookout on foollowing this kind of approach is that it would make me dynamic and also will free my developer from formating gridview and other stuffs .also i can follow up any kind of customisation using class for the grid . like for creating hyperlinkcolumns i will not have to write the html code like "Project.aspx?id={0}" but will write on the column property that column.Dataitem=constants.ProjectMaster  +  "?id={0}" ;

so that in near future if there is change in any pagename or anything i just modify the class and it is done .

Does this kind of thing could be ahcived more convieniently ...?


thanks
govind
 

jhoojharsinghyadav replied on Monday, October 08, 2007

Hi Rocky,

Currently i am working with an object say Invoice(editable root) and invoice line items (editable child objects) .
what i am trying to achive is . no database trasanction should be there until and unless the user finally push the saves button and the whole object should be saved on in 1 fly by a single querry .

to be more elaborative what i am trying is .
1. user makes entries for invoice header .
2. and starts entring the invoice line items by a ui which do have a add button and the line items are displayed in a grid , with edit and delete things .
3. as the user pushes add button the line items collections will have that item added to them , but will not have them in the databse coz no db thing should b done .
4. after completing all ,he finally saves the object and it is saved by 1 db transacton only .


what i am stucked with how to maintain the iinvoicelineitems on the fly ......


thanks
govind


RockfordLhotka replied on Monday, October 08, 2007

This is automatic. When you interact with objects all the interaction occurs in memory. Only when you call Save() on the root object does any (and all) database interaction occur, and that does typically occur in a transaction.

 

Rocky

 

From: jhoojharsinghyadav [mailto:cslanet@lhotka.net]
Sent: Monday, October 08, 2007 7:08 AM
To: rocky@lhotka.net
Subject: [CSLA .NET] Editable Root and Editable Child Object

 

Hi Rocky,

Currently i am working with an object say Invoice(editable root) and invoice line items (editable child objects) .
what i am trying to achive is . no database trasanction should be there until and unless the user finally push the saves button and the whole object should be saved on in 1 fly by a single querry .

to be more elaborative what i am trying is .
1. user makes entries for invoice header .
2. and starts entring the invoice line items by a ui which do have a add button and the line items are displayed in a grid , with edit and delete things .
3. as the user pushes add button the line items collections will have that item added to them , but will not have them in the databse coz no db thing should b done .
4. after completing all ,he finally saves the object and it is saved by 1 db transacton only .


what i am stucked with how to maintain the iinvoicelineitems on the fly ......


thanks
govind



< br>

jhoojharsinghyadav replied on Tuesday, October 09, 2007

Hi Rocky,

I dint get it exactly ,
mean when the line items add button will raise event it  will call the editablechildlist object for line itmes add method and that will add them up into the line item collection , but that should happen on in memory instead going to do the insert in lineitems table and then again refetching them .

this is being done in projecttracker refrence application .

thanks
govind

RockfordLhotka replied on Tuesday, October 09, 2007

No, when the Assign button is clicked the new item is added to the child collection in memory. It does not go to the database until Save() is called on the root object (Project or Resource).

 

In PTWeb the Save() method is called on each page request (more or less) and so the database is immediately updated. This is because most web users don’t expect to have to click a save button at the end, they expect things to save all the time.

 

But in PTWin and PTWpf the Save() method is only called when the save or apply buttons are clicked. This is because most rich client users don’t expect to have things saved automatically, and only want them saved when they say so.

 

Rocky

 

 

From: jhoojharsinghyadav [mailto:cslanet@lhotka.net]
Sent: Tuesday, October 09, 2007 1:19 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Editable Root and Editable Child Object

 

Hi Rocky,

I dint get it exactly ,
mean when the line items add button will raise event it  will call the editablechildlist object for line itmes add method and that will add them up into the line item collection , but that should happen on in memory instead going to do the insert in lineitems table and then again refetching them .

this is being done in projecttracker refrence application .

thanks
govind



jhoojharsinghyadav replied on Wednesday, October 10, 2007

hi rocky,

yes i found that code working in PTWin ,
now for  achiving the same functionality in PTWeb app i am not able to find the events such as

on save

 // stop the flow of events
        this.projectBindingSource.RaiseListChangedEvents = false;
        this.resourcesBindingSource.RaiseListChangedEvents = false;
       
        // commit edits in memory
        this.resourcesBindingSource.EndEdit();
        this.projectBindingSource.EndEdit();
        try
        {
          // clone object and save clone
          Project temp = _project.Clone();
          _project = temp.Save();

          if (rebind)
          {
            // rebind the UI
            this.projectBindingSource.DataSource = null;
            this.resourcesBindingSource.DataSource = this.projectBindingSource;
            this.projectBindingSource.DataSource = _project;
            ApplyAuthorizationRules();
          }
        }


being rasied in windows app.

could you plz throw some light on this .

RockfordLhotka replied on Wednesday, October 10, 2007

As I said, PTWeb doesn’t work this way. Web users don’t typically expect a “form level” save button. The web is (usually) stateless, and so data must be saved on every postback.

 

If you want to provide a “form level” save button in your web app, you can certainly do so. Just keep the business object in Session and manipulate it there. Then only call Save() on the root object when the user clicks the save button.

 

If you do that, I strongly recommend using a bit of javascript to prevent the user from navigating away from the page prior to clicking save. You can’t really prevent them from leaving without saving, but you can give them a dialog where they have to click OK to leave without saving.

 

Rocky

jhoojharsinghyadav replied on Thursday, October 11, 2007

Hi Rocky ,

i think i had solved the problem and had implemented the form level save button .
smotthing it more i need to call the child item validation rules be fired before a chld gets added to collection .
also on saving any contact it should at least contain one address

summing up the whole here is what the case was and how its being handled.
1. contact and addresses
    a contact can have multiple addresses
2. form level save was required as a contact can have upto 20 addresses or more and querrying for every update,entry,delete address was not required coz for of lot hits on database
3. the parent id was handled at backened i.e at database level identity field .
4. javascript to handle if user migrate without saving the object .

classes used.
1. editableroot (contact class) with an child object read only property addresseslist.
2. editablechild (address)
3 editablechildlist(addresslist)
4. addressbo

listchanged event handled in contact class causing the propertyhaschanged("address") for addresslist property.

at formview the 2 tabs
1. contact details
2. address details (textboxes + add button and a datagridview)
3. on add click the datagrid was rebinded .after the item was added to collection

now on form level save . the rooot object was saved which do returns up an identity
child objects save was called which was being done by using the xpath querry .

objects get saved successfully and edited too .

my querry is
1. is it a nice way to do so in web app .
2. fire validations for child object when any child object goes for edition or deletion .
3. want my user dont go on multiple windows for just making a simple object entry .


Finally when it will be done complete in a smother way will post the whole code , so that no other user do gets stuck for the same issue .as i was , coz i can see a lot ppl querrying for the same in forums and struggling .

thanks
govind

jhoojharsinghyadav replied on Thursday, October 11, 2007

Hello rocky ,

Ok i do saved the object in the session and had implemented the same .
when the user is in entry mode the object is new hence its saved completely.
and on add(assign) button the child gridview is again databinded so the changes are on screen with the postback .

but now coming in the update mode . the user do manipulations with the invoicelineitems and then presses save(form level save) and root objects save button is called . but here the root is not dirty so the child is also not save inspite of the fact it is dirty. not able to come out of this looop....



thanks
govind

RockfordLhotka replied on Thursday, October 11, 2007

In that case you missed the bit in Chapter 7 about overriding IsValid and IsDirty in a parent object. That is required, so the parent’s state is affected by the state of its children.

 

Rocky

 

From: jhoojharsinghyadav [mailto:cslanet@lhotka.net]
Sent: Thursday, October 11, 2007 7:07 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: Editable Root and Editable Child Object

 

Hello rocky ,

Ok i do saved the object in the session and had implemented the same .
when the user is in entry mode the object is new hence its saved completely.
and on add(assign) button the child gridview is again databinded so the changes are on screen with the postback .

but now coming in the update mode . the user do manipulations with the invoicelineitems and then presses save(form level save) and root objects save button is called . but here the root is not dirty so the child is also not save inspite of the fact it is dirty. not able to come out of this looop....



thanks
govind

Copyright (c) Marimer LLC