LINQ to SQL: Business Logic Guidance RRS feed

  • Question

  • I'm looking for some guidance for implementing non-trivial business logic requirements when using LINQ to SQL. An example case would be a requirement to ensure that an Order record never exists without one or more related OrderItem records.


    Is it recommended I implement this kind of business logic within the data context class somehow? If so, how? Adding custom logic to DataContext.InsertOrder and DataContext.DeleteOrderItem perhaps but doesn't this lead to complications if further queries are needed during a call to SubmitChanges?


    If these type of business logic requirements aren't suited to the data context then I can easily envisage implementing them in a controller class but this isn't ideal to me given that alot of RAD controls and technologies (e.g. LinqDataSource, ASP.NET Dynamic Data, ADO.NET Data Services, etc) are geared towards directly communicating with your data context.

    Friday, October 24, 2008 3:17 PM

All replies

  • Matt,


    Check out the "Domain Model" pattern if you haven't already.  The best resource is Martin Fowler's "Patterns of Enterprise Architecture".  Basicially, the idea is to put logic on the business entities themseles (which you can do, since the generated entities are all partial classes).  You can add:


    (a) Read-only properties to return values calculated from other properties

    (b) Validation methods (like something like this or this or the OnValidating method in the partial classes. I don't like the latter, because I don't like the timing of when it is called, or the fact that it is exception-based)

    (c) Methods to perform actions


    That covers the general case. As for your particular example - making sure that every order always has an order item - there seem to be two choices: 1. try to write it so that when an order is constructed it will automatically make an order line too; or 2. write it as a validation rule, in the Order entity, and perhaps make a factory method on the order class to called something like MakeOrder - which makes an order with one order line.  You'll probably have to go for option 2 in this case, because if you do option 1 it is very hard to tell the difference between "getting constructed for the first time" and "getting constructed when being read out of the DB later on".  You would only want to auto-create an order line in the first case, not the second (since it already has an order line by that time), but you can't easily tell them appart in LINQ-to-SQL.


    Don't be put off by that complexity, your particular example just happens to be an awkward one!  Virtually all other kinds of logic (a to c above) are easy to implement in the partial classes. 




    Friday, October 24, 2008 9:05 PM
  • Thank you for your suggestions. I agree with your points (a) through (c) and this approach can be used for straightforward validation. I'm trying to obtain guidance on a general approach towards non-trivial business logic. Does anyone have an opinion on the following approach?


    Code Snippet
    public class MyDataContext : DataContext {
     partial void InsertOrder(Order instance) {
      // Some arbitrary queries are required here
      // to enforce certain rules / check conditions / perform logging etc.
      // Technicalities dictate a new data context instance is required.
      using (MyDataContext db = new MyDataContext(this.Connection.ConnectionString) {
       // Run database commands using new context instance



    Note that the 'current' (aka 'this') data context instance cannot be used for the additional logic. This might be because the nature of the commands cannot be carried out during a call to DataContext.SubmitChanges. Is this a recommended way to perform such tasks? Can anyone see any disadvantages or pitfalls with this approach?


    John, I think this approach would work well with your factory method suggestion. Logic could be placed in the 'InsertOrder' and 'DeleteOrderItem' methods to query the in-memory entity and database appropriately.


    Monday, October 27, 2008 3:52 PM