Does LinqToSql Announce and Implement Best-practice DataContext?

What is the best practice for setting up my DataContext for easy access in my extended LinqToSql classes?

For example, I have a User object in my dbml, and I want to add methods to this class as follows:

Partial Public Class User Public Function GetUser(ByVal UserID as Integer) as User 'Do Work End Function End Class 

To access my DataContext, I would have to declare it inside the method as follows:

 Partial Public Class User Public Function GetUser(ByVal UserID as Integer) as User Dim dc as New MyDataContext() Return (From u in dc.Users Where u.ID = UserID).Single() End Function End Class 

I would not want to do this for each method. Usually (if I did not extend the LinqToSql dbml classes), I could just do this:

 Partial Public Class User Private dc as MyDataContext Public Sub New() dc = new MyDataContext() End Sub Public Function GetUser(ByVal UserID as Integer) as User Return (From u in dc.Users Where u.ID = UserID).Single() End Function Public Function GetAllUsers() as IEnumerable(Of User) Return From u in dc.Users End Function 'etc... End Class 

This will allow me to access the datacontext for each method without having to declare it every time. But of course you cannot do this because dbml already has a constructor. And adding code to dbml is always overwritten if anything changes.

Does anyone have any good ideas on how to save redundant code here?

TIA!

+15
linq-to-sql datacontext
Feb 14 '09 at 17:23
source share
5 answers

First, make sure you delete your DataContext when you're done! It can be a heavy little bastard ( editing is not heavy to create an instance, but hard to keep if you continue to use it without recycling); You do not want the old DataContexts to hang in memory.

Secondly, the DataContext is intended to represent a single logical transaction . For example. you must create a new one every time you want to start a new transaction, and get rid of it when this transaction is completed. So for your purposes, this is probably the scope of the GetUser method. If you have a series of database calls that need to be made as a group, they all must use the same DC before getting rid of it.

+14
Feb 14 '09 at 17:27
source share

As Rex M said , the datacontext is designed to be created, used, and used for every logical transaction. Templates of this kind are sometimes called the "unit of work."

The most common way (which I know) to do this is to create an instance of your datacontext in the used block. I haven't used VB after a while, but it should look something like this:

 Using dc As New MyDataContext() user = (From u in dc.Users Where u.ID = UserID).Single() End Using 

This not only simplifies the appearance of the transaction / unit of work (through the physical form of the code), but also provides a Dispose () call in your datacontext when the block ends.

See this MSDN page :

In general, a DataContext instance is designed to last one โ€œblock to work,โ€ however your application defines this term. DataContext - It's Easy and Not Expensive Create. A typical LINQ to SQL application creates DataContext instances in a method scope or as a member of short-lived classes, which are a logical set of related database operations.

+12
Feb 14 '09 at 17:44
source share

I think that perhaps the real problem is that User is probably not suitable for calling a member of the GetUser instance.

0
Feb 14 '09 at 17:29
source share

There are several different ways you could do this, which I think will be good practice. First, you can use the repository template in which you request a repository for an object, it goes to the database, retrieves the object - perhaps by separating it from the data context or keeping the data context depending on the implementation of the Repository - and returns it to you. The factory methods for your objects will be in the repository, not the entities themselves. You are probably using reflection and generic tools to minimize the number of methods you need to implement and save your DRY code.

Another way and the way LINQtoSQL was supposed to be used initially by IMHO is to create a data context for each set of database operations that you intend to perform. In this case, the creation of the data context occurs outside the object, usually in a class that uses entities, and not in the data layer at all. You can also add methods to the data context - make your actual data context abstract and inherit from it - use reflection again, perform some of the usual search functions so you don't have to repeat them. You will probably have to use a database template such as ActiveRecords, where the id columns always have the same name to make this work.

Alternatively, you can look at nHibernate or ActiveRecord Lock instead of repeating one of the above in your own solution.

0
Feb 14 '09 at 17:49
source share

It can be easier if you leave the User class alone and let the IDE handle its creation.

Often I prefer to have a separate class for processing data. Suppose you call it UserDataProvider, and all calls to get an instance of User ultimately go through this class.

The UserDataProvider constructor can create a global instance of the data context object for reuse. It will look something like this (in C # and unverified code, so bear with me):

 public class UserDataProvider { private UserDataContext _data = null; public UserDataProvider() { _data = new UserDataContext(); } public User GetUser(int userID) { return _data.Users.FirstOrDefault(u => u.UserID == userID); } } 

In addition, you can put initialization in a property and access this property to use the data context.

 public class UserDataProvider { private UserDataContext _dataContext; private UserDataContext DataContext { get { if (_data == null) _data = new UserDataContext(); return _data; } } public User GetUser(int userID) { return DataContext.Users.FirstOrDefault(u => u.UserID == userID); } } 
0
Feb 14 '09 at 18:28
source share



All Articles