Extending an Object Class (Best Practice)

6 posts, 0 answers
  1. Tad Carter
    Tad Carter avatar
    9 posts
    Member since:
    Feb 2008

    Posted 16 Feb 2009 Link to this post

    HI All!

    (I initially posted this as a comment to another thread in the "General" forum... but I think this is better suited for the "Getting Started" forum here as a new thread so I am adding my question here as well).

    I am looking for a little guidance... what is Telerik's recommendation on extending the object class, i.e. creating additional constructors, properties, public static functions for my business objects?

    I typically like to create:
    1) a constructor that will initialize my business object class using its unique ID,
    2) create additional private variables with associated public properites, and
    3) also would like to create some reusable business logic common functions for each business object.  

    For example, let's say I have a data table called DATPage and use Reverse Mapping feature to generate the DATPage.cs file.  I have included code sample below (stripped down version) to use as a reference. 

    DATPage.csOpen Access Reverse Mapping (automatic generated file "customized")

    1 namespace DataMine.DataAccess   
    2 {  
    3     public partial class DATPage   
    4     {  
    5  
    6     // Private local variables.  
    7     private _IsTopPage bool;  
    8  
    9     public DATPage() { } 
    10
    11 #region "Additional Constructors"  
    12     public DATPage(int page_id)    
    13     {   
    14         this.LoadByPrimaryKey(page_id);  
    15         SetDefaults(page_id);  
    16     }  
    17  
    18     private void SetDefaults(int page_id)  
    19     {  
    20         this.NavigateUrl= this.NavigateUrl + "?pg=" + page_id;  
    21         _IsTopPage = IsTopPage();  
    22     }
    23
    24 #endregion  
    25  
    26 #region "Additional Public Properties" 
    27     public int IsTopPage     
    28     {  
    29     get { return _IsTopPage; }   
    30     set { _IsTopPage= value; }   
    31     }
    32 #endregion  
    33  
    34 #region "Public Static Functions" 
    35  
    36     public static DATPage GetPageByID(int page_id)   
    37     {  
    38         string query = "SELECT * FROM DATPageExtent as c WHERE page_id=" + page_id;   
    39  
    40         IQueryResult result = ObjectScopeProvider1.GetNewObjectScope().GetOqlQuery(query).Execute();   
    41         return (DATPage)result;   
    42     }  
    43  
    44     public static List<DATPage> GetChildPageObjects(int parent_id)   
    45     {   
    46         string query = "SELECT * FROM DATPageExtent as c WHERE parent_id=" + parent_id;  
    47         IQueryResult result = ObjectScopeProvider1.GetNewObjectScope().GetOqlQuery(query).Execute();   
    48         return (List<DATPage>)result;     
    49     }  
    50 }
    51
    52 #endregion  
    53  

     

     

    Questions (best practice):

    1. Is it recommended that I put the additional constructors in the DATPage.cs file that was generated by OA Reverse Engineering (as I have done here in my sample)?  
    2. Can you provide sample code that would demonstrate how I might implement the "LoadByPrimaryKey()" method (line 14).  I am looking for a method that would populate my business object, (like a Fill() method on a datatable adapter).   Does a method exist in OpenAccess for this or is there alternate method you would recommend?
    3. I would like to store reusable "public static functions" that will return business objects, Generic Lists, DataTables etc... (for example line 36, 44).   Would you recommend that I store these functions in the generated DATPage.cs file as well or create a separate class for these, like in a file called DATPageCollection.cs perhaps?

    Any help and advice would be greatly appreciated.  

    Thanks,
    Tad

  2. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 19 Feb 2009 Link to this post

    Hi Tad Carter,
    You can do nearly implement everything you want on the persistent classes.

    What is not working is that you construct the object by yourself and let us fill the data in. We have to construct the object and will give it back to you. You can use a Query or scope.GetObjectById to load an object from the database. The scope.GetObjectById has to be used together with scope.GetObjectId to get the IObjectId instance for an existing object.

    New objects have to be created by you and to persist them you have to call scope.Add.

    Additional private variables have to be tagged as [Transient] and OpenAccess will not persist them.

    It is absolutely right to place business functions at the persistent types. This makes it possible to store real business objects in the database. please do that.

    If you have additonal questions please contact us again.

    Best wishes,
    Jan Blessenohl
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  3. DevCraft banner
  4. Tad Carter
    Tad Carter avatar
    9 posts
    Member since:
    Feb 2008

    Posted 19 Feb 2009 Link to this post

    Hello Jan!  Thanks for the reply!

    Just so I am clear, I will rephrase your answers for each question in my post. 

    Questions:
    1. Is it recommended that I put the additional constructors in the DATPage.cs file that was generated by OA Reverse Engineering (as I have done here in my sample)?   

      ANSWER: Yes, it is recommended to use the DATPage.cs file for my custom business logic (constructors).

    2. Can you provide sample code that would demonstrate how I might implement the "LoadByPrimaryKey()" method (line 14).  I am looking for a method that would populate my business object, (like a Fill() method on a datatable adapter).   Does a method exist in OpenAccess for this or is there alternate method you would recommend?

      ANSWER 2a: No, you are saying that there is no method in OpenAccess which will Fill() the object with values given a primary key.
      ANSWER 2b: The alternative to which you eluded does not work for this situation because the base class object is readonly. So, in your example using GetObjectByID(), the object returned cannot be assigned to the base class in my constructor... thus the need for the Fill() function.

       

       

    3. I would like to store reusable "public static functions" that will return business objects, Generic Lists, DataTables etc... (for example line 36, 44).   Would you recommend that I store these functions in the generated DATPage.cs file as well or create a separate class for these, like in a file called DATPageCollection.cs perhaps? 

       

      ANSWER: Yes. It sounds like you recommend that all data access business rules for each object should be included in the same class object (DATPage.cs in this case). This would include custom constructors, transient properties, persistant properties, public methods, public static methods, etc... for the object.

       

       

    Did I understand your responses correctly?  If so, regarding 2b... it sounds like there is no good way to build the constructor the way I have done it in the past.   The only reason I was asking, is that I have existing code that I am trying to maintain.

    Existing code uses this mechanism to retrieve an instance of an object:   

    DATPage p = new DATPage(page_id); 

    Sounds like I may want to replace the existing code with a helper function, GetPageByID(page_id)... does that sound like the best approach?  The new code would look something like this:

    DATPage p = GetPageByID(page_id); 

    From my understanding, I can implement the helper function in several ways: using GetObjectById(), LINQ, OQL, or standard query or stored procedure.

    Here are two options I am considering.  Is one better than the other (from a performance standpoint)?

    Using GetObjectById()

    public static DATPage GetPageByID(int page_id)  
    {  
         IObjectScope scope = ObjectScopeProvider1.GetNewObjectScope();  
         IObjectId oid = Database.OID.ParseObjectId(typeof(DATPage), page_id.ToString());  
         return (DATPage)scope.GetObjectById(oid);  
    }  
     

    Using LINQQuery

    public static DATPage GetPageByID(int page_id)  
    {  
         IObjectScope scope = ObjectScopeProvider1.GetNewObjectScope();  
         var result = from p in scope.Extent<DATPage>() where p.ID== page_id select p;  
         return (p.result.First<DATPage>();  

    I appreciate your help with this.  I am a new to Telerik, and just need a little help getting started. 

    Thanks again for your guidance holding my hand while I still have on my training wheels.
    Tad

  5. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 20 Feb 2009 Link to this post

    Hello Tad Carter,
    Thanks for clarifying my answers, you got it ;)

    I do not under stand you base class concern, if you mean the base class in your persistent model OpenAccess cares about the data in that as well.

    Using Linq or OQL or GetObjectById are equal, we are cashing the compiled query and the execution time will be the same in the second call.

    Good luck .

    Greetings,
    Jan Blessenohl
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
  6. dmajkic
    dmajkic avatar
    7 posts
    Member since:
    Mar 2007

    Posted 23 Feb 2009 Link to this post

    Since classes are generated as partial, is there anything against creating custom methods in the same class but in the other file?

    That way you could safely regenerate ORM files, and just adjust custom files when needed.
  7. Jan Blessenohl
    Admin
    Jan Blessenohl avatar
    707 posts

    Posted 24 Feb 2009 Link to this post

    Hi dmajkic,
    You can make a 3rd class file as well. If you want us to regenerate everything you just have to delete the generated files and we will generate them from scratch. You just have to keep the reversemapping.config file.

    Greetings,
    Jan Blessenohl
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Check out the tips for optimizing your support resource searches.
Back to Top
DevCraft banner