I have a dropdown on one of my webforms that needs to display a list of CostCentres filtered by UserID (the logged on user id). Could/should I modify my clsCostCentre_NVL_ByUser to pass in a UserID, which in turn will be passed as a parameter to my stored procedure?
Or should I create a readonlyroot list for this purpose?
While on the subject, the app requires a number of dropdown lists to display data that is filtered by previous selections. NVL or ReadOnlyRootList?
NVL is merely a specialized version of ROL, designed to help reduce the amount of code needed to create a name/value list.
The decision on whether to use NVL or ROL should be, I think, driven primarily by which approach allows you to write the least code. I'm guessing, in your scenarios, that NVL will still require less code, even after you create/use your custom criteria classes.
One thing about context-sensitive lists like this. They should flow from your object model. It isn't the UI's job to know what list should be filtered this way or that. That's business logic, and belongs in the business layer.
Global, unfiltered, lists can be created directly, like the roles are in ProjectTracker.
Other lists are filtered based on the state of an object. For instance, consider a Customer object. Once you pick the Region value (from a global list) the possible options for District are filtered. To implement this, the DistrictList object should NOT be available for direct creation. It is not a global, unfiltered list.
Instead, DistrictList should come from the Customer itself, because what you need is the list of districts for this customer.
Additionally, the Customer object needs the filtered list too. Otherwise, how can it validate that the District property has been set to a valid value? It must validate the input - that's business logic - and to do that it already needs the filtered list.
The result is like this:
RegionList regions = RegionList.GetList();
DistrictList districts = _customer.GetDistrictList();
If you want to have the UI automatically respond, you can handle the PropertyChanged event from _customer, and when the Region property changes you should rebind the UI to _customer.GetDistrictList().
Thanks for response.
So I understand that the filtered list should be a property of my business object.
In my scenario, I have a list (NVL) called clsCostCentre_NVL which, at present return the entire list of cost-centres (I need this as well as a filtered list)
My User class will require a CostCentres property which will return a filtered list of CostCentres based in UserID ie
public class clsUser
Public ReadOnly Property ID() As Integer
Get
CanReadProperty("ID", True)
Return m_intID
End Get
End Property
Public ReadOnly Property CostCentres() As clsCostCentre_NVL
Get
Return clsCostCentre_NVL_ByUser.GetCostCentre_NVL(m_intID)
End Get
End Property
End Class
What Im not sure how to do is modify the criteria class in the NVL class to accept a parameter. When I try to add a Partial Class Criteria in my NVL class I get a message stating that I should declare it as shadows. Advice appreciated
Terry
You need to give the criteria class a different name. NVL
already declares a class called Criteria, so you can’t use that name.
Partial classes have no place in this model at all (unless you are using a code
generator that uses Partial classes – in which case you’ll have to
resolve any differences there).
Rocky
Ive got my class to work using the code pasted below. What I have now are two distinct classes
1) clsCostCentre_NVL which is used throughout the application and is a non filtered list of CostCentres
2) clsCostCentre_NVL_ByUser which will be used by my clsUser class, which will pass in a UserID parameter to filter the list
Im a little cocerned because Im not fully sure I fully understand the call to the DataPortal.Fetch. In the clsCostCentre_NVL the factory method is:
Public Shared Function GetCostCentre_NVL() As clsCostCentre_NVL If _list Is Nothing Then_list = DataPortal.Fetch(
Of clsCostCentre_NVL)(New Criteria(GetType(clsCostCentre_NVL))) End If Return _list End FunctionIn my adapted class Ive replaced this with:
Public Shared Function GetCostCentre_NVL_ByUser(ByVal intUserID As Integer) As clsCostCentre_NVL_ByUser If _list Is Nothing Then_list = DataPortal.Fetch(
Of clsCostCentre_NVL_ByUser)(New Filter(intUserID)) End If Return _list End Function Can you foresee any problems doing things the way I have?Also, you mentioned in previous post that "Partial classes have no place in this model at all ".
Im a little concerened at this as Im using Partial classes throughout. I have one partial class for template generated code and another for custom code. Is there likely to be any problems with this?
Thanks again.
My Adapted NVL class
=================
''------------------------------------------------------------------------------
'' <autogenerated>
'' This code was generated using CSLA 2.0 CodeSmith Template Collection.
'' Changes to this file may be lost if the code is regenerated.
'' Modify user class CostCentre_NVL_ByUser.vb to extend this generated code.
''
'' Code was generated at 15/02/2007 15:12:39 by tholland
'' Template path: D:\_Development\CodeSmith\3.2\3.2 Templates\SGB CSLA.Net 2.0\NameValueList.cst
'' Template website: http://www.codeplex.com/Wiki/View.aspx?ProjectName=CSLAcontrib
'' </autogenerated>
''------------------------------------------------------------------------------
Imports
SystemImports
System.DataImports
System.Data.SqlClientImports
CslaImports
Csla.Data<Serializable()> _
Public Class clsCostCentre_NVL_ByUser Inherits Csla.NameValueListBase(Of Integer, String)
#
Region " Factory Methods " Public Class Filter Public UserID As Integer Public Sub New(ByVal intUserID As Integer)UserID = intUserID
End Sub End Class Private Sub New() ' require use of factory method End Sub Private Shared _list As clsCostCentre_NVL_ByUser Public Shared Function GetCostCentre_NVL_ByUser(ByVal intUserID As Integer) As clsCostCentre_NVL_ByUser If _list Is Nothing Then_list = DataPortal.Fetch(
Of clsCostCentre_NVL_ByUser)(New Filter(intUserID)) End If Return _list End FunctionPublic Shared Sub InvalidateCache()
_list =
Nothing End Sub#
End Region#
Region " Data Access " Protected Overrides Sub DataPortal_Fetch(ByVal criteria As Object)RaiseListChangedEvents =
False Dim objFilter As Filter = CType(criteria, Filter) Using cn As SqlConnection = New SqlConnection(Database.Contest03UKConnection) Using cm As SqlCommand = cn.CreateCommand()cn.Open()
cm.CommandType = CommandType.StoredProcedure
cm.CommandText =
"sprCostCentre_NVL_ByUser_Select_CSLA"cm.Parameters.AddWithValue(
"@intUserID", objFilter.UserID)Using dr As SafeDataReader = New SafeDataReader(cm.ExecuteReader())
IsReadOnly =
False While (dr.Read()) Me.Add(New NameValuePair(dr.GetInt32("coce_int_ID"), dr.GetInt16("coce_sin_Number"))) End WhileIsReadOnly =
True End Using End Using End UsingRaiseListChangedEvents =
True End Sub#
End RegionEnd
Class
Your code looks fine to me.
If you want, you may consider collapsing your two NVL classes
into one class, and just having two factory methods, with two overloads for
DP_Fetch(). That might keep your code simpler overall.
There’s nothing wrong with using partial classes along
with code generation – I didn’t mean to imply otherwise. My point
was that Criteria isn’t a partial class, at least in CSLA .NET itself. If
your code-gen tool is creating partial classes then that’s fine.
Rocky
Hey Rocky,
I have a similar situation where I have a combo that uses a NVL and the user can click a checkbox that will basically change the sort from "Sort By Number" to Sort By Name". The attached code works perfectly when using the Local DataPortal, but does not work when switching to the Remote DataPortal. Can you see anywhere in the code that may cause that? I am a bit baffled as to why it would matter which DataPortal is used.
Thanks in advance for your time.
Kelly.
What does "does not work" mean?
No data? An exception? If so, what kind of exception? If a DataPortalException, what's the BusinessException? Do other objects work through the remote data portal?
Hey Rocky,
Sorry I did not clarify how it did not work in the previous message. When the checkbox value is changed, the combobox blinks then appears with the previous sort order - always by number. Is it a problem with the _sortbyname member variable declared as static? If I leave the static off, I get a compile error of course. Just not sure what else to try, short of having two different BOs.
Kelly.
The problem is that you are effectively using a global variable for your sort flag. When you call the data portal, the data portal calls your DataPortal_Fetch() method IN A NEW INSTANCE OF YOUR OBJECT.
So any instance fields are obviously brand new, and empty so you can load them in DP_Fetch(). Only the criteria parameter has values from the caller.
When you use a local data portal everything runs in one AppDomain, so any static fields are available to all your code - they are global variables (and thus are basically evil btw ).
When you use a remote data portal the server code actually runs on the server - obviously then in a different AppDomain. Your static field is back on the client, and you didn't pass it to the server.
The correct answer to your problem is to create a custom Criteria class (call it SortedCriteria or something) and include the bool flag value in the criteria. Your DP_F() code should then use the value from the criteria parameter, not from a global field.
Thanks Rocky,
It worked beautifully! I knew I was missing something that was happening with the static bool member variable; I just could not figure it out - my appreciation for you and this community runs deep. Attached is what the new object code looks like, if others have experienced similar heart/headaches.
Thanks again,
Kelly.
Copyright (c) Marimer LLC