Create new objects through DataPortal_Fetch?

Create new objects through DataPortal_Fetch?

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


hurcane posted on Wednesday, September 06, 2006

I don't want the client of an object to have to know whether it is creating a record or fetching an existing record. If the record exists, we want to use it. If it does not exist, we want to always create a new record. In both cases, the DataPortal has to go to the database. Currently, we have code like this inside the shared Factory method of the business object:

Dim return as myObject
return = myObject.GetMyObject(id)
If return Is Nothing Then
    return = myObject.NewMyObject(id)
End If
Return myObject

The client also has some other logic that depends on whether IsNew is true. Mainly, some fields are read-only if the object is not new.

Since I always have to hit the database, I want to combine the two DataPortal calls into a single call. Within the DataPortal_Fetch, it was trivial to combine the code, including calls to MarkOld and MarkNew, as appropriate. However, I discovered that my object was still coming back as an "old" object because the DataPortal calls MarkOld for us automatically after the call to the DataPortal_Fetch method.

I think I can resolve this issue with the following changes to my object:
However, I'm not sure that this is the right path to go. I'm wondering if I should create a ReadOnly factory object that returns my real business object through it's own DataPortal_Fetch call. Then, my logic stays the same within my object, but the logic will always be running on the application server because it is being instantiated through the separate factory object.

If you had this problem, which solution would you choose?

Brian Criswell replied on Wednesday, September 06, 2006

If  I understand you, you want a single method of retrieving an object so that it creates or fetches as appropriate, but when you tried to combine them in the DataPortal, you ran into problems.  You are now looking at making non-standard changes to CSLA methods.

Personally, I would take the simple option of having the factory method choose the correct DataPortal method to call.

public Object GetObject(Guid id)
{
    if (Object.Exists(id))
       return DataPortal.Fetch<Object>(new Criteria(id));
    else
       return DataPortal.Create<Object>(new Criteria);
}

If the Exists() call to the database is really going to be too much of a hit, then call DataPortal.Create() and then add a call to MarkOld() when appropriate.

DansDreams replied on Wednesday, September 06, 2006

I don't like DataPortal calling MarkOld() precisely for this reason - I think it makes too big an assumption for code at that low a level, but anyway...

I'd vote for something like Brian's solution mainly because it keeps things very clean and simple even if not quite as efficient in database traffic (it's still the same amount of work at the database though).

 

 

hurcane replied on Thursday, September 07, 2006

Brian Criswell:

Personally, I would take the simple option of having the factory method choose the correct DataPortal method to call.

public Object GetObject(Guid id)
{
    if (Object.Exists(id))
       return DataPortal.Fetch<Object>(new Criteria(id));
    else
       return DataPortal.Create<Object>(new Criteria);
}

If the Exists() call to the database is really going to be too much of a hit, then call DataPortal.Create() and then add a call to MarkOld() when appropriate.


This is essentially what I am doing now, which creates two calls to the database. Some of our clients are operating in a WAN environment, and we are finding that the round-trip time is a significant portion of the response time. Having two round trips is what I am trying to eliminate.

After having had a night of sleep, I think I am going to wrap the creation inside of a separate ReadOnlyBase-derived factory object. I'll change the GetObject factory method to call the separate factory object. This will give me one round trip and I won't have to change the client usage.

RockfordLhotka replied on Thursday, September 07, 2006

I would recommend creating a ROB-derived factory object that goes to the server, gets the object you want and returns with it (new or old). This ROB object doesn't need to be public, so it doesn't clutter your namespace, and is an elegant solution to the problem. So your factory looks like this:

public static Object GetObject(Guid id)
{
  return ObjectFactory.GetObject(id)
}

[Serializable]
private class ObjectFactory : ReadOnlyBase<ObjectFactory>
{
  private Object _result;
  public Object Result
  { get { return _result; } }

  public static Object GetObject(Guid id)
  {
    ObjectFactory factory = DataPortal.Fetch<ObjectFactory>(new Criteria(id));
    return factory.Result;
  }
  // implement criteria and DataPortal_Fetch()
}

Copyright (c) Marimer LLC