I have implemented CSLA for middle tier. And all works fine. But now I need custom SQL Query, very complicated query. So I made a method where I pass one string parameter. Inside that method I write query and try to get data from database. And data returned are fine. But the problem is when I get object and change some property value and call "MyCslaObject.Save()" instead of Update new row is added to table. Why I get saving new row instead update, what am I doing wrong?
I get object with using following code:
using (SqlConnection connection = new SqlConnection(ADOHelper.ConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(commandText, connection))
{
using (var reader = new SafeDataReader(command.ExecuteReader()))
{
if (reader.Read())
{
myObject= MyObject.NewMyObject();
myObject.p1= (int?)reader["xx"];
myObject.p2= (int?)reader["xx"];
myObject.p3= (DateTime?)reader["xx"];
myObject.p4= (DateTime?)reader["xx"];
myObject.p5= reader["xx"].ToString();
myObject.p6= (int)reader["xx"];
}
...
Your fetch of an existing object should involve typically a factory method (GetCustomer) on the customer class, along with a call to DataPortal.Fetch. This will go through the CSLA code which will invoke your DataPortal_Fetch method in your business object.
DataPortal_Fetch is an instance method, and the instance is an object that is _not_ marked as new. You hydrate your business object similar to how you're doing it above (but using LoadProperty so that you do not go through the property setters & trigger validation and mark the object as dirty). In the end you have a non-new object and when you change values on the client and save, it'll recognize it as "not new" and go through the DataPortal_Update code when save is invoked.
But the bottom line is you're going through a factory method that probably calls DataPortal_Create or in some way ends up having IsNew = true. When this happens, your save of the business object will be routed through DataPortal_Insert and the object will go through insert instead of update logic.
You shouldn't typically invoke the "New" factory method of an object within the DataPortal_Fetch code (if that's where this code is).
What type of object is the MyObject? is it a root object or a child object?
Assuming that it is a root object your SQL code should be placed inside a DataPortal_Fetch method or an ObectFactory class.
should look like:
myObject = MyObject.GetMyObject(criteria);
and within MyObject you would have:
public static MyObject GetMyObject(string criteria)
{
return DataPortal.Fetch<MyOrder>(criteria);
}
protected void DataPortal_Fetch(string reader)
{
using (SqlConnection connection = new SqlConnection(ADOHelper.ConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(commandText, connection))
{
using (var reader = new SafeDataReader(command.ExecuteReader()))
{
if (reader.Read())
{
using (BypassPropertyChecks)
{
this.p1= (int?)reader["xx"];
this.p2= (int?)reader["xx"];
this.p3= (DateTime?)reader["xx"];
this.p4= (DateTime?)reader["xx"];
this.p5= reader["xx"].ToString();
this.p6= (int)reader["xx"];
}
}
}
}
}
Hi,
Thanks but I am missing one thing here. Instead of criteria I need to pass custom sql query to execute. Something like:
SELECT TOP(1) x, y, z from table t1 join t2 on t1.x = t2.y where someColumn = (SELECT TOP(1) ...) ORDER BY someColumn
So what you are saying is that the SQL Command Text is passed in as a parameter (criteria)?
Sure - you can use the supplied string as the SQL command - beware of possible SQL Injection tho'.
Copyright (c) Marimer LLC