none
Why not static/shared methods on the entities RRS feed

  • Question


  • Q: Where should I put my business logic?  The system I’m currently developing uses static methods on the entities themselves for loading, saving and other operations.

    A: The DataContext conforms to the Unit of Work design pattern.  A work context must exist and be maintained separate from the entities themselves.  You should either place all your business logic as methods on the DataContext or devise a separate business context that encapsulates a DataContext instance.  You should not be using static methods.



    Can someone please explain this a bit further? In my application I have placed my business logic on the "entities". First all validation are done in the "onvalidate". Further I have created instance methods like


    public function Insert()

    using db as new datacontext

    db.customers.insertonsubmit(me)

    db.submitchanges()

    end using

    This enables me to write this in my code:

    MyNewCustomer.Insert()

    and shared methods like

    datacontext.customer.getMostValueableCustomer()

    Why is this approach wrong ?  

    TC


    Thursday, March 27, 2008 3:19 PM

Answers

  • There is nothing inherently wrong with your approach, if you constrain all units of work to simple operations on single entities.  Many applications do this.  The DataContext was designed to track and understand changes made to many entities at once. It has built in heuristics to know how to order all interdependent inserts, updates and deletes automatically.  Imagine an application that allows you to edit a bunch of data that is technically spread over many objects.  Instead of a UI that requires you to submit one change before moving onto the next you it allows you the freedom to make all the edits you think are necessary at once. With the 'method on the entity' approach, you have to independently know which entities were editted, which actually need to be updated and in which order to update them to keep all the database constraints happy, requiring you to bake in specific data model knowledge into your application code.  The DataContext does this for you, requiring you only to call SubmitChanges once. 

     

    Retrieving entities from static methods is likewise problematic.  Of course, again, nothing is inherently wrong if you only ever use single entities at a time, and your entities don't define relationships that form networks of objects in memory.  You can happily load one, edit it and save it away.  The problem comes when you want to build an application that loads multiple entities that have direct relationships between each other and multiple requests for the same entity actual return the same instance.  When you load entities from different DataContext instances (as happens when you create a new one in each static method), the entities exist in different object-graph universes. You can't use them together because they are managed and tracked by different contexts.  For example, if you separately load a customer and order entity and bind them to some UI form, and then later navigate from the order to its 'customer' via the order's customer property, you'll get a new and different customer instance, not the one you loaded previously, and not the one you allowed the user to edit.

     

    To make it work correctly, you need to keep using the same DataContext instance for the entire 'unit of work' that you are operating on.  Nothing is stopping you from putting data access logic on entities.  However, in order to do it correctly, you should pass a DataContext as a parameter to these methods. Once you've done that, the rest is just style.

     

    Thursday, March 27, 2008 4:32 PM
    Moderator

All replies

  • There is nothing inherently wrong with your approach, if you constrain all units of work to simple operations on single entities.  Many applications do this.  The DataContext was designed to track and understand changes made to many entities at once. It has built in heuristics to know how to order all interdependent inserts, updates and deletes automatically.  Imagine an application that allows you to edit a bunch of data that is technically spread over many objects.  Instead of a UI that requires you to submit one change before moving onto the next you it allows you the freedom to make all the edits you think are necessary at once. With the 'method on the entity' approach, you have to independently know which entities were editted, which actually need to be updated and in which order to update them to keep all the database constraints happy, requiring you to bake in specific data model knowledge into your application code.  The DataContext does this for you, requiring you only to call SubmitChanges once. 

     

    Retrieving entities from static methods is likewise problematic.  Of course, again, nothing is inherently wrong if you only ever use single entities at a time, and your entities don't define relationships that form networks of objects in memory.  You can happily load one, edit it and save it away.  The problem comes when you want to build an application that loads multiple entities that have direct relationships between each other and multiple requests for the same entity actual return the same instance.  When you load entities from different DataContext instances (as happens when you create a new one in each static method), the entities exist in different object-graph universes. You can't use them together because they are managed and tracked by different contexts.  For example, if you separately load a customer and order entity and bind them to some UI form, and then later navigate from the order to its 'customer' via the order's customer property, you'll get a new and different customer instance, not the one you loaded previously, and not the one you allowed the user to edit.

     

    To make it work correctly, you need to keep using the same DataContext instance for the entire 'unit of work' that you are operating on.  Nothing is stopping you from putting data access logic on entities.  However, in order to do it correctly, you should pass a DataContext as a parameter to these methods. Once you've done that, the rest is just style.

     

    Thursday, March 27, 2008 4:32 PM
    Moderator
  • Now I understand a bit more Smile

    Given the following scenario:

    You have 2 aspx pages
    CreateCustomer.aspx
    This page have 2 textboxes "name", "phone" and a button "submit"

    'Create a new customer(customertable) with a name and a phone (in a phonetable)
    private sub onsubmit()

    end sub

    EditCustomer.aspx
    This page is identical to createcustomer but it works on a given customerid.

    'Fill customername and phone into textboxes - Get customerid from querystring
    private sub form_load

    end sub

     'Send the updated customername and phone back to DB.
    private sub onsubmit()

    end sub


    You have a datacontext named DB and two entities "Customer" and "Phone"

    Suppose you want the pages to be as "disconnected" as possible from the application logic, not performing any selecting, updating by themself. Where would you place the linq insert, select, and updatecode? Is it "correct" to create a datacontext at the page level and call submitchanges directly? If that is the solution one quickly end up with doing the selecting also.

     sub form load
    using d as new db
    cust=(from c in d.customers select d).first
    textbox1.text=cust.customername
    textbox2.text=cust.phones.first.phoneNr
    end using
    end sub


    Which is what I am trying to avoid by creating shared/static functions doing the work. But, as you mentioned in the previous post - That is not a good solution either Smile

    TC
    Friday, March 28, 2008 9:05 AM