cslaDataSource and resusable namevaluelistcslaDataSource 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.aspxPlease 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
govindRockfordLhotka 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