Frage

I have a class that handles all database operations. I've read that it's better to use multiple DataContext instances for different read/write/update/delete operations as opposed to one DataContext instance that lives a long time.

That means every function that does read/write/update/delete on the DB needs to do this:

    public int GetSomeID(string name)
    {
        using (XXDataContext context = new XXDataContext(connStr))
        {
            ...
        }
    }

    public int GetAnotherID(string name)
    {
        using (XXDataContext context = new XXDataContext(connStr))
        {
            ...
        }
    }

    public void WriteSomething(string text)
    {
        using (XXDataContext context = new XXDataContext(connStr))
        {
            ...
        }
    }

opposed to having this using() only in constructor and having the context as a private member variable available to every function call.

With keeping the functionality of creating a new DataContext with every function call, is it possible to move this using() somewhere else so not every single function has to have this line in it?

War es hilfreich?

Lösung

You can use a method like this to avoid re-writing the using code:

private static void WithContext(Action<XXDataContext> action)
{
    using(XXDataContext context = new XXDataContext(connStr))
        action(context);
}    
private static T WithContext<T>(Func<XXDataContext, T> function)
{
    using(XXDataContext context = new XXDataContext(connStr))
        return function(context);
}

This allows you to write:

public int GetSomeID(string name)
{
    WithContext(context => 
        {
            //TODO use context
        });
}

If that helps you.

Andere Tipps

Sorry for not answering your question directly:

You have read right thing. Context implements Unit Of Work pattern and supposed to be used like that.

However there can be a valid case when you need to do several operations within the same context and it would've been nice to right code like that:

using(var dal = new MyDalUOW()) {

   dal.Delete(s1);
   dal.Update(s2);
   dal.Get(s3);

   dal.Commit()
}

In order to have this you will create your Dal class which will implement IDisposable and will have method Commit

public class BaseDal: IDisposable {
   private MyDbContext _context;

   public BaseDal() { _context = new MyDbContext; }

   public void Commit() { _context.SaveChanges(); }
}

And all your methods will use _context to perform operation.

So you will still have all those usings but in code using your DAL, not in the DAL itself.

If you use it in desktop/windows application it is no problem to have single DataContext, but you have to handle it wisely (according to the db technology, eg. EF or linq2sql) against synchronizing the datacontext cache data with database. And the one thing more, you have to use separate datacontext per thread.

I you use it in WEB app (ASP NET) then it is recommended and it is good practise to create a new instance of the datacontext per request (and dispose it on finish the request).

So it depends on your solution.

Alright, consider this code:

using (var fileStream = new FileStream(@"C:\temp\test.txt", FileMode.Open))
{
    var bytes = new byte[fileStream.Length];
    fileStream.Read(bytes, 0, (int)fileStream.Length);

    var text = Encoding.Default.GetString(bytes);

    Console.WriteLine(text);
}

It leverages a class that uses IDisposable; just like the DataContext. Now, let's say we'd like to get rid of that using; we can do this:

Read(fileStream =>
{
    var bytes = new byte[fileStream.Length];
    fileStream.Read(bytes, 0, (int)fileStream.Length);

    var text = Encoding.Default.GetString(bytes);

    Console.WriteLine(text);
}, @"C:\temp\test2.txt");

static void Read(Action<FileStream> action, string path)
{
    using (var fileStream = new FileStream(path, FileMode.Open))
    {
        action(fileStream);
    }
}

Here you are injecting the code you want to execute while ensuring that the using statement is removed from the method. Further, you can guarantee that the using statement is going to be used. The output of this program is as expected:

Hello, World!
Hello, World; from an injected function!
Press any key to continue . . .
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top