Should NVL objects for dropdowns be inside Business Objects?

Should NVL objects for dropdowns be inside Business Objects?

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


NightOwl888 posted on Thursday, January 10, 2008

I realize this might be a question that "depends on your situation", but I am just trying to get my head around the best way to approach this scenario.  Basically, I like the way Rocky designed this framework to get all of the database data in one shot. That is - unless you are also including the dropdown lists on the UI, then it seems like you need to make another round trip for each one.

I realized this when designing a project that I made a couple years ago and ended up putting the NVL objects inside the business objects.  While this seems to solve the round-trip problem, it also means that I will always pull up the NVL data whether I am binding to a UI or not.

An example would be having a Product object that belongs to a specific Category.  The Product object technically only needs to know the assigned CategoryID.  However, for the user to select it on the UI, they will need a dropdown list filled with all of the CategoryIDs and Category Names. So, is it generally acceptable to pull up the list of CategoryIDs and Names every time we get an instance of a Product, whether it is used by the UI or not? Technically speaking, the Category NVL doesn't belong to the Product, it is only required to select the value that does belong.

I am just curious if anyone uses this approach and if there are any known drawbacks to it other than the extra overhead involved.

robert_m replied on Friday, January 11, 2008

As I see it, CategoryList should be a separate class. If you are worried about extra trips to the server side to load it with data, then you might perhaps consider some caching techniques ? In practice, data in many lookup tables is quite static which makes them good candidates for caching.

 

rsbaker0 replied on Thursday, February 21, 2008

robert_m:

As I see it, CategoryList should be a separate class. If you are worried about extra trips to the server side to load it with data, then you might perhaps consider some caching techniques ? In practice, data in many lookup tables is quite static which makes them good candidates for caching.

Yes, we basically use "lazing loading" for these where they are loaded only on the first request for the factory method (GetList() in our case), and then from then on they stay around for the duration of the application. Subsequent calls just immediately return the one already fetched.

 

RockfordLhotka replied on Thursday, February 21, 2008

Here’s some pseudo-code that shows the basic concept.

 

public class Record

{

    [NonSerialized]

    private OfficeList _officeList;

    [Browsable(false)]

    public int OfficeList

    {

      get

      {

        if (_officeList == null)

          _officeList = OfficeList.GetList(this.Company);

        return _officeList;

      }

    }

 

    [NonSerialized]

    private DepartmentList _departmentList;

    [Browsable(false)]

    public int DepartmentList

    {

      get

      {

        if (_departmentList == null)

          _departmentList = DepartmentList.GetList(this.Office);

        return _departmentList;

      }

    }

 

    private static PropertyInfo<int> CompanyProperty = RegisterProperty<int>(typeof(ProjectResource), new PropertyInfo<int>("Company"));

    public int Company

    {

      get { return GetProperty<int>(CompanyProperty); }

      set { SetProperty<int>(CompanyProperty, value); }

    }

 

    private static PropertyInfo<int> OfficeProperty = RegisterProperty<int>(typeof(ProjectResource), new PropertyInfo<int>("Office"));

    public int Office

    {

      get  { return GetProperty<int>(OfficeProperty); }

      set { SetProperty<int>(OfficeProperty, value); }

    }

 

    private static PropertyInfo<int> DepartmentProperty = RegisterProperty<int>(typeof(ProjectResource), new PropertyInfo<int>("Department"));

    public int Department

    {

      get { return GetProperty<int>(DepartmentProperty); }

      set { SetProperty<int>(DepartmentProperty, value); }

    }

 

    protected override void AddBusinessRules()

    {

      ValidationRules.AddRule<Record>(InvalidateOfficeList<Record>, CompanyProperty);

      ValidationRules.AddRule<Record>(InvalidateDepartmentList<Record>, OfficeProperty);

 

      ValidationRules.AddDependentProperty(CompanyProperty, OfficeProperty);

      ValidationRules.AddDependentProperty(CompanyProperty, DepartmentProperty);

      ValidationRules.AddDependentProperty(OfficeProperty, DepartmentProperty);

    }

 

    private static bool InvalidateOfficeList<T>(T target, RuleArgs e) where T: Record

    {

      target._officeList = null;

    }

 

    private static bool InvalidateDepartmentList<T>(T target, RuleArgs e) where T: Record

    {

      target._departmentList = null;

    }

}

jfreeman replied on Thursday, April 10, 2008

I’ve used the logic you sent below to build the object built when I try to use this object in BusinessListBase (I want to show all the Record values in a list) I cannot get it to change Office values.  For instance, the 1st five records have the same Company and Office.  The 6th value has the same Company but the office is different.  I cannot get it to select the correct value in the Office on the change.  Does that make sense?  Thanks for your help.

_________________________________________________
Jonathan Freeman| LBMC Technologies, LLC
5250 Virginia Way| 3rd Floor | Brentwood, TN 37027
p: 615.309.2447 | f: 615.309.2747 | jfreeman@lbmc.com

 

From: Rockford Lhotka [mailto:cslanet@lhotka.net]
Sent: Thursday, February 21, 2008 11:39 AM
To: Jonathan Freeman
Subject: RE: [CSLA .NET] Should NVL objects for dropdowns be inside Business Objects?

 

Here’s some pseudo-code that shows the basic concept.

 

public class Record

{

    [NonSerialized]

    private OfficeList _officeList;

    [Browsable(false)]

    public int OfficeList

    {

      get

      {

        if (_officeList == null)

          _officeList = OfficeList.GetList(this.Company);

        return _officeList;

      }

    }

 

    [NonSerialized]

    private DepartmentList _departmentList;

    [Browsable(false)]

    public int DepartmentList

    {

      get

      {

        if (_departmentList == null)

          _departmentList = DepartmentList.GetList(this.Office);

        return _departmentList;

      }

    }

 

    private static PropertyInfo<int> CompanyProperty = RegisterProperty<int>(typeof(ProjectResource), new PropertyInfo<int>("Company"));

    public int Company

    {

      get { return GetProperty<int>(CompanyProperty); }

      set { SetProperty<int>(CompanyProperty, value); }

    }

 

    private static PropertyInfo<int> OfficeProperty = RegisterProperty<int>(typeof(ProjectResource), new PropertyInfo<int>("Office"));

    public int Office

    {

      get  { return GetProperty<int>(OfficeProperty); }

      set { SetProperty<int>(OfficeProperty, value); }

    }

 

    private static PropertyInfo<int> DepartmentProperty = RegisterProperty<int>(typeof(ProjectResource), new PropertyInfo<int>("Department"));

    public int Department

    {

      get { return GetProperty<int>(DepartmentProperty); }

      set { SetProperty<int>(DepartmentProperty, value); }

    }

 

    protected override void AddBusinessRules()

    {

      ValidationRules.AddRule<Record>(InvalidateOfficeList<Record>, CompanyProperty);

      ValidationRules.AddRule<Record>(InvalidateDepartmentList<Record>, OfficeProperty);

 

      ValidationRules.AddDependentProperty(CompanyProperty, OfficeProperty);

      ValidationRules.AddDependentProperty(CompanyProperty, DepartmentProperty);

      ValidationRules.AddDependentProperty(OfficeProperty, DepartmentProperty);

    }

 

    private static bool InvalidateOfficeList<T>(T target, RuleArgs e) where T: Record

    {

      target._officeList = null;

    }

 

    private static bool InvalidateDepartmentList<T>(T target, RuleArgs e) where T: Record

    {

      target._departmentList = null;

    }

}



 
 
Privacy Notice

"The information contained in this message may be privileged and confidential and protected from disclosure. If the reader of this message is not the intended recipient, or an employee or agent responsible for delivering this message to the intended recipient, you are hereby notified that any dissemination, distribution or copying of this communication is strictly prohibited.  If you have received this communication in error, please notify us immediately by replying to this message and deleting it from your computer."
 
Thank you. 
The LBMC Family of Companies

jgamba replied on Friday, November 14, 2008

I am implementing the solution proposed by Rocky, but I've had issues.

Using the same example, I have three lists (CompanyList, OfficeList and DepartamentList) filled with their respective properties (Company, Office and Department) assigned.

1. If I change the selected company in the combobox, the InvalidateOfficeList rule is thrown so _officeList is null, however, the OfficeList property is never consulted and therefore does not change the content of the combobox office.

2. Each of my lists have one instance DefaultValue property, which is assigned each time GetList() is called and according to the provided parameter (this.Company, this.Office). as its name indicates, DefaultValue must determine which item is selected initially, so if the user changes the company selected, the Record business object must automatically and cascading gets the remaining lists (OfficeList and DepartamentList) and assign the properties and Office Department.

Which is the most appropriate way to deal with these issues?

Thanks in advance

Jorge Gamba

ajj3085 replied on Friday, November 14, 2008

It looks like you have the "combo B has different elements depending on what element in combo A is selected," and you're on WinForms, correct?

That seems to be a huge PITA.. I've found that while the BO is correct, the combo box B doesn't like to "blank" itself even though the value is now empty; I've handled this by having an event handler for combo A which sets SelectedIndex to -1.   That seems to work... unless I have the problem misunderstood. Smile [:)]

jgamba replied on Friday, November 14, 2008

Thank you very much for your response

Yes, I am using WinForms

Best describe my use case with the following example, this time using a hierarchy composed as follows:

Countries
    Regions
        Cities

I have a root object 'Localization' which has the properties RegionList and CityList similarly as Rocky suggested earlier in this post.
Of course, the user could choose not to change the country but from region to begin the process, or just change the city.




simon_may replied on Tuesday, November 18, 2008

Excuse me tagging on to this thread. My BOs expose some namevalue lists as  properties that i bind a comboBox dartasource property to, However the act of binding the datasource alters the SelectedValue property which is not desirable. Having traced the databinding process I can see the SelectedValue binding then the DataSource binding which alters the SelectedValue.

Anyone have any ideas as to how I should be doing this properly

Regards

Simon

ajj3085 replied on Wednesday, November 19, 2008

I'm not sure I follow; that sounds like what the combobox is supposed to be doing.

simon_may replied on Wednesday, November 19, 2008

I started a new thread http://forums.lhotka.net/forums/thread/20326.aspx has more explanation

alef replied on Monday, December 01, 2008

example of City, Country and Region of how I implemented it:

Most of the code is generated with codesmith templates.

Maybe what is interesting is the code in bold: I added to the City class a property Country in a lazy way loading.

So it is possible for the person who is using the business layer to write something like Employee.City.Country.

But in the code the way I implemented everytime the database will be hit. Does somebody have an idea how to avoid that?

Another question what is the relationship between city, country and region. I've treated them as seperated root objects. Is that correct?

 

using System;

namespace Fim.HR.JL.Bus.Components
{
 [Serializable()]
 public partial class City : Csla.ReadOnlyBase<City>
 {
  public int CityId { get; private set; }
  public string CountryId { get; private set; }
  public string Name { get; private set; }
  public string Description { get; private set; }
  public string CreatedBy { get; private set; }
  public DateTime Created { get; private set; }
  public string ModifiedBy { get; private set; }
  public DateTime? Modified { get; private set; }

  internal static City GetCity(Fim.HR.JL.Dat.Components.City data)
  {
   City item = new City();
   item.Fetch(data);
   return item;
  }

  private City()
  { /* require use of factory method */ }

  #region Data Access
  private void Fetch(Fim.HR.JL.Dat.Components.City data)
  {
   bool cancel = false;
   OnFetching(ref cancel);
   if (cancel) return;

   CityId = data.numCityId;
   CountryId = data.strCountryId;
   Name = data.strName;
   Description = data.strDescription;
   CreatedBy = data.strCreatedBy;
   Created = data.datCreated;
   ModifiedBy = data.strModifiedBy;
   Modified = data.datModified;

   OnFetched();
  }

  partial void OnFetching(ref bool cancel);
  partial void OnFetched();
  #endregion //Data Access
 }
}

 

using System.Linq;
using Csla;
using Csla.Data;
using Csla.Security;
using Csla.Validation;
using Fim.HR.JL.Dat.Components;

namespace Fim.HR.JL.Bus.Components
{
 public partial class City : Csla.ReadOnlyBase<City>
 {
    public static City GetCity(int? id)
    {
        if (id == null)
        {
            return null;
        }

        return DataPortal.Fetch<City>(new SingleCriteria<City, int?>(id));
    }

    private void DataPortal_Fetch(SingleCriteria<City, int?> criteria)
    {
      if (criteria.Value != null)
      {
        using (var mgr = ContextManager<Fim.HR.JL.Dat.Components.HRJLDataContext>
              .GetManager(Database.HRJL, false))
        {
          var data = (from r in mgr.DataContext.Cities
                      where r.numCityId == criteria.Value
                      select r).SingleOrDefault();

          if (data != null)
            Fetch(data);

        }//using
      }
    }

    public Country Country
    {
      get
      {
        return Country.GetCountry(CountryId);
      }
    }

 }
}
-----------------------------------------COUNTRY-------------------------------------

using System;

namespace Fim.HR.JL.Bus.Components
{
 [Serializable()]
 public partial class Country : Csla.ReadOnlyBase<Country>
 {
  public string CountryId { get; private set; }
  public string RegionId { get; private set; }
  public string Name { get; private set; }
  public string Description { get; private set; }
  public string CreatedBy { get; private set; }
  public DateTime Created { get; private set; }
  public string ModifiedBy { get; private set; }
  public DateTime? Modified { get; private set; }

  internal static Country GetCountry(Fim.HR.JL.Dat.Components.Country data)
  {
   Country item = new Country();
   item.Fetch(data);
   return item;
  }

  private Country()
  { /* require use of factory method */ }

  #region Data Access
  private void Fetch(Fim.HR.JL.Dat.Components.Country data)
  {
   bool cancel = false;
   OnFetching(ref cancel);
   if (cancel) return;

   CountryId = data.strCountryId;
   RegionId = data.strRegionId;
   Name = data.strName;
   Description = data.strDescription;
   CreatedBy = data.strCreatedBy;
   Created = data.datCreated;
   ModifiedBy = data.strModifiedBy;
   Modified = data.datModified;

   OnFetched();
  }

  partial void OnFetching(ref bool cancel);
  partial void OnFetched();
  #endregion //Data Access
 }
}

using System.Linq;
using Csla;
using Csla.Data;
using Csla.Security;
using Csla.Validation;
using Fim.HR.JL.Dat.Components;

namespace Fim.HR.JL.Bus.Components
{
 public partial class Country : Csla.ReadOnlyBase<Country>
 {
    public static Country GetCountry(string id)
    {
      return DataPortal.Fetch<Country>(new SingleCriteria<Country, string>(id));
    }

    private void DataPortal_Fetch(SingleCriteria<Country, string> criteria)
    {
      if (!string.IsNullOrEmpty( criteria.Value) )
      {
        using (var mgr = ContextManager<Fim.HR.JL.Dat.Components.HRJLDataContext>
              .GetManager(Database.HRJL, false))
        {
          var data = (from r in mgr.DataContext.Countries
                      where r.strCountryId == criteria.Value
                      select r).Single();

          CountryId = data.strCountryId;
          RegionId = data.strRegionId;
          Name = data.strName;
          Description = data.strDescription;
          CreatedBy = data.strCreatedBy;
          Created = data.datCreated;
          ModifiedBy = data.strModifiedBy;
          Modified = data.datModified;

        }//using
      }
    }

 }
}

---------------------------------REGION-----------------------------------------

using System;

namespace Fim.HR.JL.Bus.Components
{
 [Serializable()]
 public partial class Region : Csla.ReadOnlyBase<Region>
 {
  public string RegionId { get; private set; }
  public string Name { get; private set; }
  public string Description { get; private set; }
  public string CreatedBy { get; private set; }
  public DateTime Created { get; private set; }
  public string ModifiedBy { get; private set; }
  public DateTime? Modified { get; private set; }

  internal static Region GetRegion(Fim.HR.JL.Dat.Components.Region data)
  {
   Region item = new Region();
   item.Fetch(data);
   return item;
  }

  private Region()
  { /* require use of factory method */ }

  #region Data Access
  private void Fetch(Fim.HR.JL.Dat.Components.Region data)
  {
   bool cancel = false;
   OnFetching(ref cancel);
   if (cancel) return;

   RegionId = data.strRegionId;
   Name = data.strName;
   Description = data.strDescription;
   CreatedBy = data.strCreatedBy;
   Created = data.datCreated;
   ModifiedBy = data.strModifiedBy;
   Modified = data.datModified;

   OnFetched();
  }

  partial void OnFetching(ref bool cancel);
  partial void OnFetched();
  #endregion //Data Access
 }
}

 

 

 

 

 

 

 

 

 

 

alef replied on Monday, December 08, 2008

To avoid loading the Country several times I implemented the following in the City class :

public Country Country

{

   get

   {

      if (!countryLoaded)

      {

         country = Country.GetCountry(CountryId);

         countryLoaded = true;

      }

      return country;

   }

}

 

Or can I use the fieldmanager for that? But pay attention City inherits from Csla.ReadOnlyBase.

City is a child of CityList :

using System;

using System.Linq;

using Csla;

using Csla.Data;

using Fim.HR.JL.Dat.Components;

namespace Fim.HR.JL.Bus.Components

{

[Serializable()]

public partial class CityList : Csla.ReadOnlyListBase<CityList, City>

{

#region Factory Methods

private CityList()

{ /* require use of factory method */ }

public static CityList GetCityList()

{

return DataPortal.Fetch<CityList>();

}

#endregion //Factory Methods

#region Data Access

#region Data Access - Fetch

private void DataPortal_Fetch()

{

bool cancel = false;

OnFetching(ref cancel);

if (cancel) return;

using (var mgr = ContextManager<Fim.HR.JL.Dat.Components.HRJLDataContext>

.GetManager(Database.HRJL,false))

{

RaiseListChangedEvents = false;

IsReadOnly = false;

this.AddRange(

from row in mgr.DataContext.Cities

select City.GetCity(row)

);

IsReadOnly = true;

RaiseListChangedEvents = true;

}//using

 

OnFetched();

}

partial void OnFetching(ref bool cancel);

partial void OnFetched();

#endregion //Data Access - Fetch

#endregion //Data Access

}

}

 

ben replied on Friday, January 11, 2008

Hi,

I absolutly agree with robert_m

Ben

richardb replied on Friday, January 11, 2008

I believe it's good for encapsualtion and the lists are cached anyway so a round trip to the database only occurs the first time a list needs to be used, or when the list changes (if using the latest CSLA).

 

Yes...I mean that the NVL class will be seperate but you'd still have properties in the BO to access it as per the other posts here.

JoeFallon1 replied on Friday, January 11, 2008

I tend to create a Use Case Controller object to handle the requirements. This is simply a normal Root BO which contains the Product BO as well as the NVLs for the use case. When I create a New instance of the controller object it fetches the Product and NVLs. I can add rules to the controller BO if it needs to verify data across more than one contained object. When I save the controller it doesn't usually save any data itself, it orchestrates the saving of the data in the contained BOs.

This keeps your Product object clean. Then it can be re-used in any other Use Case or UI without fear that it will contain a bunch of NVLs which are not needed in the other cases.

I would create a 2nd controller BO to contain a Product object if it required different NVLs (or other BOs) than the first Use Case.

Joe

 

ben replied on Friday, January 11, 2008

A simpler solution may be using the Factory pattern combined with the Singleton pattern:

 

Public Class ProvidersNVL

      Inherits NameValueListBase(Of System.String, System.String)

     

#Region " Singleton Pattern "

 

      Protected Shared mList As ProvidersNVL

     

      Public Shared Function GetList() As ProvidersNVL

            If mList Is Nothing Then

                  mList = ActiveObjects.DataPortal.Fetch(Of ProvidersNVL)

            End If

           

            Return mList

      End Function

 

      Public Shared Sub InvalidateCache()

            mList = Nothing

      End Sub

     

#End Region ' Singleton Pattern

 

...

 

End Class

 

With this example the business layer and the UI layer can do the following every time the list is needed. By this way all objects can share the same information:

 

Dim list As ProvidersNVL

list = ProvidersNVL.GetList

 

In our application we have many business objects sharing many NameValueLists (for instances CountriesNVL, ProvidersNVL, CustomersNVL, …) and all of them are loaded on demand and cached. You may have an Invoice BO that may need the CustomersNVL to validate its CustomerID property and you may have a DataForm with a ComboBox that uses the same CustomersNVL. But you may have many scenarios where both objects (the Invoice and its DataForm) are used and no one of them needs the CustomersNVL so you can avoid loading every NameValueList that may be used in any one of them. We always try to follow the lazy loading philosophy.

 

Ben

NightOwl888 replied on Friday, January 11, 2008

Joe,

I think you came up with an interesting solution to this issue.  You are seperating even more business logic from the UI by having your Use Case BO decide which NVLs and BOs to load and save.  This makes things simple on the UI because only one object reference is required.

However, it doesn't seem like you are accomplishing this any different than if it were in the UI directly. Namely, you are still making round trips to the database for each NVL. Correct me if I am wrong.

It still seems like this pattern could be used to handle even more complexity than just loading NVLs.  Let's test this. Let's say instead of having a simple NVL to run the dropdown, we have a Read-Only collection with 4 other values we are interested in saving with the main BO.

Going back to our product object, let's say we have a "Size" dropdown and each size changes the SKU of the product to something else. Furthermore, each size adds or subtracts an amount to the price.  So in this example if the user selects the size they want from the dropdown, we will need to save the SizeID (primary key), the size description (for use on the invoice), the SKU Fragment (what part of the SKU will change to - this will require additional business logic), and a price adjustment field.

It seems like in this example, you could have your Use Case BO handle all of the logic of changing the SKU and the price as well as pulling the other two fields from the ReadOnlyList to populate in ShoppingCart object.  Or do you think in this (more complex) case it would make more sense to encapsulate all of this business logic inside of the Product object by including the ReadOnlyList inside of the Product?

 

My problem is even more complex than this is, but I am just trying to see if this solution can be used to simplify some of the complexity.

-NightOwl888

JoeFallon1 replied on Saturday, January 12, 2008

"However, it doesn't seem like you are accomplishing this any different than if it were in the UI directly. Namely, you are still making round trips to the database for each NVL. Correct me if I am wrong."

The above statement is correct. The major differece is that the UI is "dumb" in one case and "too smart" in the other. I think we want a "dumb" UI so that when it comes time to build a new one we don't have to transfer a lot of logic from the old UI to the new one.

 

As far as round trips to the DB - I tend to want to get the values from the DB without caching. (They change a lot.) But there is nothing preventing you from caching these NVLs and then have the controller BO fetch them from the cache. It is a preference.

===================================================================

"...would make more sense to encapsulate all of this business logic inside of the Product object by including the ReadOnlyList inside of the Product?"

No. It would only make sense if the Product object *always* needs the ROC in every Use Case. You might re-use the same controller object because you have some use cases which overlap.

===================================================================

"It still seems like this pattern could be used to handle even more complexity than just loading NVLs."

It is. <g>
I load root BOs with complex hierarchies, ROCs, NVLs, etc. All the different BOs which are required to satisfy the use case.

===================================================================

When you have an NVL inside a Use Case Controller BO, you fetch it and bind the values to the screen. But you *unbind* the selected value into one of your other BOs (the FK.)

===================================================================

You sample with the ROC is more complex than an NVL. But the same ideas could apply. In this case you should decide if you really need an ROC at all or whether the Use Controller will fetch those 4 values instead. The controller BO could then bind them to the UI and let the user change all the values and then decide what to do with them later. Whereas if you just have an ROC the user can't really modify the values.

If you only want the user to select an ID from the dropdown and then you look up that row in the ROC and "transfer" all the data to your other BO   - that seems reasonable to me.

The bottom line is that the Controller BO can centralize all the activity for this Use Case.

Joe

 

RockfordLhotka replied on Saturday, January 12, 2008

I use the following guideline:

If the NVL is the same regardless of context or business object data, then I implement a factory directly on the NVL.

If the NVL is different depending on the context or business object data, then I implement a property on the context/business object to return the appropriate NVL.

 

Consider a list of country codes. In many cases such a list will be the same at all times, and so should be globally and directly available.

list = CountryCodes.GetList()

But then consider a list of country codes where a product can be sold. Some products might have restrictions on export/import/etc. This is very dependent on the OrderLineItem object (as an example), and so the list should come from that object:

list = _order.LineItems[42].ValidCountryCodes

 

jfreeman replied on Wednesday, February 20, 2008

I have a scenario where I could potentially have 3 NVLs.  When the user creates a record they have to choose Company, Office & Department.  Company is easy.  The list is always the same.  Office is filtered by which Company they choose.  Department is filtered by which Company & Office they choose.  What is the best way to handle this type logic?  Thanks.

Jonathan

RockfordLhotka replied on Wednesday, February 20, 2008

As per the earlier content of the thread, your Company object can be a root object.

But your Office and Department objects should exist within some other root object. You say the user is creating a "record", so let's call that a Record object.

The Record object should expose OfficeList and DepartmentList properties, which return appropriately filtered lists.

The Record object also has Company, Office and Department properties - presumably getting and setting the key values from the three NVL objects. When the Company property is set that would trigger reloading the OfficeList and DepartmentList NVL properties, and revalidation of the Office and Department properties (because they might no longer be valid at all now).

tna55 replied on Thursday, February 21, 2008

Rocky,

The way I have done this in my project is to have three NVL classes, CompanyNVL, CompanyOfficeNVL and OfficeDepartmentNVL. I get these NVL with factory methods e.g.

Dim mCompanyList As CompanyNVL = CompanyNVL.Load()

Dim mOfficeList As CompanyOfficeNVL = CompanyOfficeNVL.Load(CompanyID)

Dim mDepartmentList As OfficeDepartmentNVL = OfficeDepartmentNVL.Load(OfficeID)

Is this correct by design?

Tahir

RockfordLhotka replied on Thursday, February 21, 2008

Yes, that’s exactly what I do.

 

But the “Record” object in the example needs to validate the Office and Department properties, so it needs access to the properly filtered lists, so it must already have a containment relationship with those objects, so it is reasonable for it to provide navigation to those pre-filtered objects as well.

 

So I tend to make those particular factories Friend/internal, thus forcing the UI developer to go through my “Record” object – ensuring they get the correct filtering for each specific Record.

 

Rocky

 

 

From: tna55 [mailto:cslanet@lhotka.net]
Sent: Thursday, February 21, 2008 7:13 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Should NVL objects for dropdowns be inside Business Objects?

 

Rocky,

The way I have done this in my project is to have three NVL classes, CompanyNVL, CompanyOfficeNVL and OfficeDepartmentNVL. I get these NVL with factory methods e.g.

Dim mCompanyList As CompanyNVL = CompanyNVL.Load()

Dim mOfficeList As CompanyOfficeNVL = CompanyOfficeNVL.Load(CompanyID)

Dim mDepartmentList As OfficeDepartmentNVL = OfficeDepartmentNVL.Load(OfficeID)

Is this correct by design?

Tahir



jfreeman replied on Thursday, February 21, 2008

Rocky,

What you describe makes sense but being fairly new to CSLA I'm not sure how to code that in the object.  Are there any code examples that would help clarify how to implement this logic?  Thanks.

Jonathan

jfreeman replied on Thursday, February 21, 2008

When you say the Company should be a root object, do you mean it should a Business Base or NVL?  Where should the logic be that gets triggered to reload OfficeList and DeptartmentList?  If it is in the Record object, what would that logic look like?  Thanks.

Jonathan

Copyright (c) Marimer LLC