tags:

views:

87

answers:

3

Originally, I was using my DataContext object as a global singleton. When using this in ASP.Net, I was running into issues with contention because of the multi-threaded nature of ASP.Net.

So I did some searching for better alternatives, and found Rick Strahl's post about "per object" scenario. So each of my objects would have a DataContext local to the class.

So I have most of it figured out, but my question comes up when trying to get an instance of the object. Since all of the methods are instance methods, I need to get an instance of the Class first. Then I can use that instance to call the instance method to get the object that I want.

Something like this..

 Customer cust = new Customer();
 cust = cust.GetCustomer(primaryKeyID); // gets data using LINQ-To-SQL

This just seems redundant to me to create an instance of the class just to call a method to return the actual instance that I want. Is this the correct way of doing this? I would think there is a different way that still adheres to the methodology that Rick uses in his blog post.

Sample class code:

 public partial class Customer
 {
      MyDataContext db = new MyDataContext(Settings.MyConnectionString);

      public Customer GetCustomer(Int64 custID)
      {
           return db.Customers.SingleOrDefault(c => c.ID == custID);
      }

      public Customer AddCustomer(Customer c)
      {
           db.Customers.InsertOnSubmit(c);
           db.SubmitChanges();
      }
 }
+1  A: 

The sample class code doesn't close the connection at all. So it leaves the connetion waiting for the garbage collector to clean it up.

Connections are cheap because they're pooled. For the pool to work efficiently, keep connections open for as short a time as possible. I usually open a connection just to execute a single function, like:

using (MyDataContext db = new MyDataContext(conStr))
    return db.Customers.SingleOrDefault(c => c.ID == custID);

The using statement makes sure the connection is returned to the pool when the function returns.

Andomar
By default, LINQ-To-SQL opens and closes the connection on it's own. http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/90dc4a62-7316-4791-9db8-056c21153b84/You can test this by evaluating the 'db.Connection.State'. It is closed after the query is executed. See Image http://img690.yfrog.com/img690/1577/124201094248am.png
Eclipsed4utoo
@Eclipsed4utoo: Interesting. The call to `SingleOrDefault()` must allow that. But if you return halfway an IEnumerable, I don't think LINQ would know enough to close the connection. So using `using` is a good practice
Andomar
+2  A: 

To address only the question about redundancy, without commenting on the whole context-per-object philosophy or Rick's code, which I haven't reviewed,

You can eliminate the two lines with

var customer = new Customer().GetCustomer(primaryKeyId);

Alternatively, create a factory that acts as a static gateway:

public static class CustomerFactory
{
   public static Customer BuildCustomerWithId(_<int/short/long>_ primaryKeyId)
   {
      var customer = new Customer();
      return customer.GetCustomer(primaryKeyId);
   }
}

Not only does this clean up your object creation (now you just call var customer = CustomerFactory.BuildCustomerWithId(1);), but now you can modify the BuildCustomerWithId() method, if necessary, without changing the consuming classes. For example, you might later decide you don't like instantiating the DataContext in the business objects, and you refactor it all out. You can instantiate the DataContext in the factory instead, and you don't have to change any code that calls BuildCustomerWithId(). Static gateway makes unit testing slightly more challenging, but still much easier than instantiating Customer objects directly.

I realize that this doesn't solve the problem of first instantiating and then calling the getter method, but frankly, I don't see that as a problem from a performance standpoint -- only in terms of syntax/readability.

Jay
A: 

If you don't want to create an instance of a Class to get the instance of the object, you could change the GetCustomer method to static.

public partial class Customer
{
    public static Customer GetCustomer(Int64 custID)
    {
        using (var db = new MyDataContext(Settings.MyConnectionString))
        {
            return db.Customers.SingleOrDefault(c => c.ID == custID);
        }
    }
    ...
}

And you can use the method like this:

Customer cust = Customer.GetCustomer(primaryKeyID);
ferpaz