Hi everyone. This is my first post. Thank you Rocky for the excellent framework. I have read the VB2003 and part of the VB2005 BO books
I'm working with CSLA 2.1.4 in VS2005.
Background: I have is doing a Dataportal Fetch, where the object searches two databases for data. If it doesn't find its data in the new database store, it searches the prior database store.
Issue: If the object gets its data from the old data store, I try the Me.MarkNew within the Dataportal_Fetch method, so I can simply get the object, and do a save, and have it persist itself to the new data store.
Within the Dataportal_Fetch method, IsSavable method shows true after I call Me.MarkNew, but back in the UI, the IsSavable property on my object is now false.
Any ideas?
Perhaps others will consider this an interesting issue. It might be addressed in Rocky's book, which I will consult and post on the forum if I resolve this issue myself prior to anyone's replies.
Nickalis
Update:
This is also related to IsNew, because my 'workaround' of changing a property after fetching the object still doesn't help, because the IsNew is showing false.
So the bottom line is I have to have the MarkNew method work within the DataPortal_Fetch.
Nickalis
My Solution:
In order to permit MarkNew to work in the Fetch method it seems I have to comment the following line from SimpleDataPortal.vb
Fetch function, line 120 : MethodCaller.CallMethodIfImplemented(obj, "MarkOld")
This creates more work because (like in CSLA 1.x ), I'll have to call MarkOld after each Fetch from the new data store.
Nickalis
P.S. any comments I'd love to hear them!
Thanks ajj3085 , I just posted and saw that you had posted a few minutes ago.
In answer to your post, I'm not actually returning a literal new object from the Fetch method, I'm returning an existing 'object' using data from a (soon to be) obsolete data store, when it doesn't exist yet in the new data store.
Nickalis
Thanks for the replies Andy. I'll keep that in mind. One of the issues in our system is that the criterion changes depending on which system I'm drawing data from, so the Factory Method of yours, using a single criteria parameter, wouldn't work in this case.
For future posterity of the CSLA community, I'll summarize my problem and solution.
Problem: All data must be migrated from an old db system to a new database system.
Solution: What I call "On-Demand, Non-Destructive Migration" of data:
That means the initial fetch for all object data will be from the old system, and each object is considered new to the new db, which means each object's first Save() must perform a Dataporal_Insert against the new database (not a Dataportal_update to the old system), since they don't yet exist in the new system.
After the each object has saved itself to the new db, the 2nd and subsequent Fetch calls must retrieve it from the new system.
Using the CSLA 2.1.4 framework, this is an example Dataportal_Fetch I made, which follows Rocky's ProjectTracker Fetch call methodology, with one exception: When the object Fetches data from the old system, it calls Me.MarkNew, and when the object Fetches data from the new system, it calls Me.MarkOld. This requires a change to the SimpleDataPortal class as mentioned previously in this thread.
BEGIN CODE ------------------------------------------------------------------------------
Private Overloads Sub DataPortal_Fetch(ByVal criteria As Criteria)Debug.Print(
"=== Supplier.DataPortal_Fetch") If Not criteria.Id.Equals(Guid.Empty) Then 'JM.NET Fetch Using cn As New SqlConnection(Database.MasterListsConnection)cn.Open()
Using cm As SqlCommand = cn.CreateCommand With cm.CommandType = CommandType.StoredProcedure
.CommandText =
"getSupplier".Parameters.AddWithValue(
"@ID", criteria.Id) 'SP returns the Supplier object Using dr As New SafeDataReader(.ExecuteReader) If dr.Read() ThenDebug.Print(
"Against " & Database.MasterListsConnection) Dim ThisSupplier As Supplier = Deserialize(dr.GetValue("Object")) With ThisSuppliermId = .Id
mFriendlyName = .FriendlyName
mCompanyName = .CompanyName
mAddress = .Address
mCity = .City
mStateProvince = .StateProvince
mPostalCode = .PostalCode
mCountry = .Country
mContact1 = .Contact1
mContact2 = .Contact2
mPhone = .Phone
mFax = .Fax
mNotes = .Notes
End Withdr.GetBytes(
"LastUpdated", 0, mTimestamp, 0, 8) 'After Fetching the object, Mark it as old Me.MarkOld() End If End Using End With End Using End Using Else 'Try JM97 Fetch If criteria.Name.Trim.Equals("") Then Throw New ArgumentNullException("Blank Criteria") Else Using cn As New OleDb.OleDbConnection(My.Settings.PURCHConnectionString) Dim cmd As New OleDb.OleDbCommand("Select * From Suppliers Where Supplier = '" & criteria.Name.Trim & "'", cn)cn.Open()
Dim dr As New SafeDataReader(cmd.ExecuteReader()) While dr.ReadmId = Guid.NewGuid
mFriendlyName = dr.GetString(1)
mCompanyName = mFriendlyName
mAddress = dr.GetString(2)
mCity = dr.GetString(3)
mStateProvince = dr.GetString(4)
mPostalCode = dr.GetString(5)
mCountry = dr.GetString(6)
mContact1 = dr.GetString(7)
mContact2 = dr.GetString(8)
mPhone = dr.GetString(9)
mFax = dr.GetString(10)
mNotes = dr.GetString(11)
Exit While End Whiledr.Close()
End Using 'DEVNOTE: For all JM97 FETCH, YOU MUST MARK THE OBJECT AS NEW, SO IT WILL BE SAVABLE INTO JM.NET Me.MarkNew() End If End If End SubEND CODE ------------------------------------------------------------------------------
I love this framework !!! Nickalis
Nick,
MarkOld() is called by the DataPortal. You could opt to call MarkNew() in the factory method, just after the call to DataPortal.Fetch().
You could have a private field/property MustMarkNew (or something like that) which would be set in the DataPortal_Create(). If the data came from the old datastore, you should set this property to true. Then, in the factory method, you can call MarkNew() on the object before it is returned to the client.
Using this solution, you don't have to change the CSLA framework.
Cheers,
Herman
Herman,
You had me excited for a moment.
That's excellent... except the factory method is a shared method, and from it I couldn't access an instance field (mMarkNew) accessible to Dataportal_Fetch.
Or did I miss something?
Nick
ajj3085:public static MyObject Get( string id ) {
MyObject result;
result = DataPortal.Fetch<MyObject>( new IdCriteria( id ) );
result.MarkNew();
return result;
}
This is exactly what I meant.
Herman
Nick,
For what it is worth - I also commented out that line of code in the framework.
It was a major change in behavior from CSLA 1.x. There was a long discussion about it in an old thread and I was out voted. In the original code the developer was resposnible for calling (just like they are still responsible for calling it for child objects.)
In my fetch method I do some testing and if the data is not in the DB I decided to return a New object instead of throwing an exception. This was debated earlier on in CSLA 1.x and seemed like a legitimate choice. So my templates and BOs have used this logic for 3-4 years now. The call to MarkOld in the framework code broke this. So I commented it out and simply call it inside my templates when needed.
Joe
Andy,
I am not planning on changing fetch at this time.
I have about 63 Root BOs and 5 other developers working on a large application with a few hundred web pages. Making the change and then re-coding and re-testing each page to ensure that the Exception is caught would be a large effort with little payback.
I am hoping to upgrade all the BOs from 1.x to 2.x as soon as we put the current version to bed. That is also another large exercise that we never seem to find time for. New features and functions always come faster than maintenance and upgrade of framework code.
I have added Base classes bewteen CSLA 2 and my BOs so that many of my previous changes are now part of my Base classes and I do not have to comment out or modify too many things in the framework. I like that Rocky has allowed us to Override many methods now.
For example he shortcircuits the IsValid call on child objects whenever he finds the first broken rule. But I need all objects checked for validity so that prior rules get unbroken and I can build a complete list of broken rules. So my BusinessListBase class has this code:
Public
Overrides ReadOnly Property IsValid() As BooleanJoe
Copyright (c) Marimer LLC