I need urgent help on custom queries in CSLA

I need urgent help on custom queries in CSLA

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


vladakg85 posted on Monday, October 10, 2011

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"];
                        }

...

skagen00 replied on Monday, October 10, 2011

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).

JonnyBee replied on Monday, October 10, 2011

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"];
                            }
                      }
                }
          }
     }

vladakg85 replied on Tuesday, October 11, 2011

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

JonnyBee replied on Tuesday, October 11, 2011

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