locked
When to create a new DataContext

    Question

  • Hello,

    In my app I create a new instance of my DataContext object (created using Linq to SQL) and then do some querying etc using it. Whilst doing this, I call a custom function that I wrote for one of the tables also created using Linq to SQL. Inside this function, I need a reference to a DataContext. Do I:

    1. Create a new DataContext within the function?

    2. Pass in the existing DataContext as a parameter?

    If you create a new DataContext when one already exists, what happens? I want to reuse the existing datacontext, but would rather avoid passing around references to it for the sake of readability and tidyness.

    Many thanks,

    Ben S

     

    Example:

     

     

    Code Block

    //My command line application

    class Program

    {

    static void Main(string[] args)

    {

    MyDataContext db = new MyDataContext();

     

    db.MyTables.MyCustomFunction();

     

    //Maybe this should be:

    //db.MyTables.MyCustomFunction(db);

    }

    }

     

    //////////////////////////MyDataClasses.cs//////////////////

     

    //Created by Linq to SQL

    public partial class MyDataContext : DataContext

    {

    public System.Data.Linq.Table<MyTable> MyTables

    {

    get

    {

    return this.GetTable<MyTable>();

    }

    }

    }

     

    //Created by Linq to SQL.

    [Table(Name="dbo.MyTable")]

    public partial class MyTable

    {

    //A custom function that I wrote

    public void MyCustomFunction()

    {

    //Do something that needs a reference to a DataContext here

    //Do I create a new DataContext here, or do I pass in the existing one

    //   that I created in the main program?

    }

    }

     

     

     

    Friday, November 30, 2007 12:08 PM

Answers

  • You'll most often want a new context for every interesting unit of work.  DataContext's should be short lived if they can be. The only scenario where you'd keep a DataContext around for a long time would be if you were bulding the equivalent of a 2-tier UI based data-entry/editting appliction. You keep the DataContext around to enable automatic change tracking.

     

    If you are separating things into multiple phyisical tiers, you should not keep the DataContext around longer that it takes to retrieve all the data you need to gather or submit-changes.

     

    You should not be creating new DataContexts to retrieve individual objects as in an active record pattern.  It is possible to do so, but works against the design of LINQ to SQL, so you'll end up doing more work than necessary and use very little of the product.

    Saturday, December 01, 2007 7:53 PM

All replies

  • Hi Ben,

     

    The advice I have seen (and have been following for the most part) is to keep the lifetime of the data context relatively short and focused on the unit of work you are doing.  So you wouldn't want to keep a live data context around for the duration of your app and use that for all subsequent LINQ calls.

     

    I just responded to a thread of yours and mentioned a business object that I created that wrapped some LINQ to SQL off an established data context.  I'll expand on the pattern I've been following and let you decide if you wish to follow it (and possibly some of the hardcore LINQ guys will respond with comments and/or other (better) approaches).

     

    I have mainly avoided extending my LINQ to SQL generated classes with custom functions, aside from simple things like calculated values (e.g. a FullName property based on FirstName and LastName properties).  I view the LINQ to SQL generated classes as the data access layer (DAL) itself, and any calculated properties would extend this and be part of the DAL.

     

    When I want to query the DAL, I will usually encapsulate the LINQ to SQL code in a business object layer made up of business objects that encapsulate a data context.  So I'll typically have a parameterless constructor for the business object that instantiates its own data context, and a constructor that takes a data context as a parameter, but regardless of how the BO is constructed, all LINQ to SQL wrapped in its methods will use the data context instance variable.  This allows me to pretty much forget about the data context and not have to worry about passing it around all the time (except when I feel that I need to and will pass an existing data context as a parameter to the constructor).

     

    Code Block

    public class EnterpriseBo

    {

    public EnterpriseBo()

    {

         // Calls a static method that instantiates a new data context

         // based on a connection string already read from app.config

         // (maintained by a custom connection string manager class)

    db = EnterpriseDataContext.NewContext();

    }

     

    public EnterpriseBo(EnterpriseDataContext DataContext)

    {

    db = DataContext;

    }

     

    protected EnterpriseDataContext db;

    }

     

    public class MachineBo : EnterpriseBo

    {

    public MachineBo()

    : base()

    {

    }

     

    public MachineBo(EnterpriseDataContext DataContext)

    : base(DataContext)

    {

    }

     

    public Machine ByMacAddress(string MacAddress)

    {

    Machine machine = db.Machines.SingleOrDefault(m => m.MacAddress == MacAddress);

     

    return machine;

    }

     

    // Other methods that usually join against multiple tables, return custom

    // defined types (that can be serialized across WCF), etc.

    }

     

    Hope this helps.

     

    -Larry

     

     

    Friday, November 30, 2007 1:55 PM
  • First of all, there is a mistake in your code. You've added a method MyCustomFunction to your entity class MyTable and expect to have this method available on your LINQ to SQL table MyTables  which is of type Table<MyTable>. This is wrong and your code won't compile.

    Regarding your question, it's better not to have more than one instance of the same type of DataContext pointing to the same database in your application as it may cause several mistakes and bugs in your code. For example, if you load a record from one DataContext, trying to save its changes on the other one won't work. The only safe way of having several DataContexts in your application at the same time is turning off change tracking(via ObjectTrackingEnabled property) and deferred loading (via DeferredLoadingEnabled property) on all your DataContexts which of course disables important parts of its functionality. So, it's better not to maintain more than one instance of DataContext in your application unless you have strong reasons to do so.

    Regarding your problem keeping your code neat when sharing the same instance of DataContext in various parts of the application is making it static or sharing it via a singleton class. For example you can write:

    public static class SharedElements
    {
    public static MyDataContext DB { get; private set; }

    static SharedData()
    {
    DB = new MyDataContext();
    }
    }


    And use SharedElements.DB wherever in your code that needs a reference to the DataContext.
    Friday, November 30, 2007 2:44 PM
  • Thanks for your responses - very helpful.

     

    (yes, I must have been asleep when I wrote the example!)

     

    I will be using a DataContext in the context of an ASP.NET Page, and therefore it will only be used briefly whilst the page is being rendered and then disposed of.

     

    Thanks again,

    Ben

    Friday, November 30, 2007 5:08 PM
  • It is inevitable that there will be cases where multiple contexts will be looking at the same database.  ASP.NET, as mentioned, is one.  You're not going to get away from this fact.  This is why we have optimistic concurrency support in LINQ to SQL.

     

    So don't be afraid of having multiple data contexts -- just be aware that multiple contexts may exist, and in general treat them appropriately. 

     

    In particular:

    Realize that the data is stale the moment it's queried. (This is why long-lived contexts are problematic.)

    and

    Never assume that two contexts agree about the state of any particular row in the database.

     

    Failure to do so is what would lead to problems as alluded to in CompuBoy's response.

     

    Friday, November 30, 2007 6:58 PM
  • You'll most often want a new context for every interesting unit of work.  DataContext's should be short lived if they can be. The only scenario where you'd keep a DataContext around for a long time would be if you were bulding the equivalent of a 2-tier UI based data-entry/editting appliction. You keep the DataContext around to enable automatic change tracking.

     

    If you are separating things into multiple phyisical tiers, you should not keep the DataContext around longer that it takes to retrieve all the data you need to gather or submit-changes.

     

    You should not be creating new DataContexts to retrieve individual objects as in an active record pattern.  It is possible to do so, but works against the design of LINQ to SQL, so you'll end up doing more work than necessary and use very little of the product.

    Saturday, December 01, 2007 7:53 PM
  • Hey Matt,

     

    How are you invisioning the datacontext to be used? A business facade that wraps around and hides the context or as a source that can be used by the presentation layer? The LinqDataSource seems to imply presentation layer.

     

    Paul

    Monday, January 07, 2008 11:10 PM