CSLA 2.0 - Create OR Fetch

CSLA 2.0 - Create OR Fetch

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


Smeat posted on Thursday, May 11, 2006

Hi

I'm developing a small app using CSLA 2.0 where the use case is as follows:

The user selects a date from the calendar, the system then loads the existing record (can only be 1)  for that date. If no record exists then a new one is created.

In this scenario, my business object must first check if a record exists and if so, load it (DataPortal_Fetch). If no record exists then a new record is created (DataPortal_Create). Note that when no record exists, I cannot physically create that record until the user has entered the required data.

My question is how do I cater for this scenario within my business objects?

I was thinking of placing the logic within my factory method as follows:

public static MyObj CreateOrLoadObj(DateTime dt)

{

   MyObj o = new MyObj();

   o.DataPortal.Fetch(new Criteria(dt));

   if(o.ID > 0)

   {

      //We have an existing record

   }

   else

   {

      //No existing record so create new one.

      o = new MyObj();

      o.Create(new Criteria(dt));

   }

   return o;

}

Does this look like the write approach? I think my main concern is that on calling the factory method, the object is remoted over then network to load the existing object and then returned to the client. If no existing record exists, then the object is again remoted over the network and a new MyObj is created before sending the object back over the network to the client.

Is there a better way of doing this?

TIA

Smeat

 

glenntoy replied on Thursday, May 11, 2006

Hmm.. I hope I'm right with my idea in my mind... Big Smile [:D]

A suggestion you might use the <RunLocal()> attribute in DataPortal_Create() if you are sure that all creates are to be run in the client.

So it will be something like this

<RunLocal()> _
Private Overloads Sub DataPortal_Create(ByVal criteria As Criteria)
    ' your implementation here
End Sub

I think RunLocal() will force you to run in your client..

P.S. I'll be late in checking your replies because we are in different timezones.

DavidDilworth replied on Thursday, May 11, 2006

Are you actually doing anything inside your DataPortal_Create()?  If not then all you might need is a single call to DataPortal_Fetch().

Surely the criteria passed to the DataPortal_Fetch() will not return any data if there is nothing to get (i.e. there isn't already an item).

If this is the case, then what you have is an object that has already been instantiated (by the DataPortal) with all the default settings for your BO.

You will only need to set the fields within your BO if you actually get data back from the DB.

It's not a "purist' usage of the DataPortal_Fetch(), but there doesn't seem to be any reason why you shouldn't be able to take advantage of this "feature" of a DataPortal_Fetch() when the criteria returns an empty record set.

Perhaps you can try it to see if it works?

Bayu replied on Thursday, May 11, 2006

Hi all,

Let me throw another suggestion into the mix, just for the fun of comparing possible solutions. Smile [:)]

- purist thinking: is this actually business logic? Isn't it actually a use case with two scenario's .... more like a UI responsibility to check for existence (using a shared Exists() member on the particular BO ...).

Ok, this was just crap, this is possibly 'pure' from an OO point of view but will result in 2 DB hits (Exists + Fetch or Exists + Create).

- practical thinking: I am a great fan of (ab)using stored procs, they weren't invented for nothing, right? So, assuming you want to load some defaults from the DB for your dp_create, you can design a stored proc that always returns the item that was requested for by the date-key AND the default values.  This would result in two SELECT statements in one stored proc which returns two tables in your result set. The pro is that this will reduce your DB hits to 1, while the con is that you will transfer some (very small amount though) extra data (those defaults) with every single call.

- That was assuming you need to load defaults from the DB, otherwise you can just do as previously mentioned: mark your dp_create with the runlocal attribute. This would leave only 1 DB hit which may or may not return data for a particular date-key.



Plenty of options I guess, none of it are 'pure' but all of them are practical. So which one to choose? Stick out tongue [:P]

Bayu

glenntoy replied on Friday, May 12, 2006

Smeat, if your new object doesn't have to retrieve any values from DB proceed to RunLocal() attribute. As what you said if there is an existing record it will return only 1 row. Combining the comments of Bayu and David, you can do it like this

Public Shared Function GetBusBaseName(ByVal id As Integer) As BusBaseName
  Dim o as BusBaseName = DataPortal.Fetch(Of BusBaseName)(New Criteria(id))
  
  'Exists is a readonly property name whos value will be set in the DataPortal.Fetch .... mExists = dr.Read()
  If o.Exists Then
    Return o
  Else
    Return DataPortal.Create(Of BusBaseName)(New Criteria(id))
  End If

End Function

Copyright (c) Marimer LLC