Showing posts with label LinqToSql. Show all posts
Showing posts with label LinqToSql. Show all posts

Monday, September 30, 2013

LINQ to SQL DataContext BeginTransaction

LINQ to SQL supports Transactions, but there is no method directly off of the DataContext to initialize one. Fortunately, that functionality is just a simple extension method away!

public static class DataContextExtensions
{
    public static IDbTransaction BeginTransaction(
        this DataContext dataContext, 
        IsolationLevel isolationLevel = IsolationLevel.Unspecified)
    {
        if (dataContext.Connection.State != ConnectionState.Open)
            dataContext.Connection.Open();
 
        return dataContext.Transaction = dataContext.Connection
            .BeginTransaction(isolationLevel);
    }
}
 
public class TransactionTests
{
    [Fact]
    public void Example()
    {
        using (var dataContext = new FutureSimpleDataContext())
        using (dataContext.BeginTransaction())
        {
            // TODO: Stuff!
        }
    }
}
Shout it

Enjoy!
Tom

Tuesday, September 25, 2012

Func Injection in Unity

Let your container be your factory. :)

If you are using LinqToSql and dependency injection, then you have probably created a factory with which you create DataContexts. But what if you could just let your IOC Container do that work for you? You can!

If you are using Unity then you can inject a Func<T> of any registered type. Unity will automatically bind the injected Func to the container's resolve method, thus preserving the resource Lifetime Manager.

Example Code

public class FuncInjectionTests
{
    [Fact]
    public void TransientLifetimeFuncIsThreadsafe()
    {
        var container = new UnityContainer();
 
        container
            .RegisterType<IUserService, UserService>(
                new ContainerControlledLifetimeManager())
            .RegisterType<IDataContext, DataContext>(
                new TransientLifetimeManager());
 
        var parallelOptions = new ParallelOptions {MaxDegreeOfParallelism = 100};
 
        Parallel.For(0, 1000, parallelOptions, i =>
        {
            var userService = container.Resolve<IUserService>();
 
            Parallel.For(0, 1000, parallelOptions, j =>
            {
                userService.Update();
            });
        });
 
        Assert.Equal(1, UserService.Count);
        Assert.Equal(1000000, DataContext.Count);
    }
}
 
public interface IUserService
{
    void Update();
}
 
public interface IDataContext : IDisposable
{
    void UpdateUser();
}
 
public class UserService : IUserService
{
    public static int Count;
 
    private readonly Func<IDataContext> _dataContextFactory;
 
    public UserService(Func<IDataContext> dataContextFactory)
    {
        _dataContextFactory = dataContextFactory;
        Interlocked.Increment(ref Count);
    }
 
    public void Update()
    {
        using (var dataContext = _dataContextFactory())
            dataContext.UpdateUser();
    }
}
 
public class DataContext : IDataContext
{
    public static int Count;
 
    public DataContext()
    {
        Interlocked.Increment(ref Count);
    }
 
    public void UpdateUser()
    {
        Trace.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + Count);
    }
 
    public void Dispose()
    {
    }
}
Shout it

Enjoy,
Tom

Saturday, August 18, 2012

Linq to Sql Batch Future Queries

Batch queries are crucial feature of any good ORM...including LinqToSql!

Future queries are an unobtrusive and easy to use way of batching database queries into a lazy loaded data structures. Future queries were originally a feature of NHibernate, and have since been ported to other ORMs. However I am currently working on a project where I do not have access to those tools.

Thus I created LinqToSql.Futures, a simple extension that adds batched futures queries to LinqToSql.

Using Future Queries

  1. Get the LinqToSqlFutures NuGet package.
  2. Extend your DataContext to implement IFutureDataContext. (This is optional, see below!)
  3. Use future queries!

To batch queries together, simply call the ToFuture extension method on your IQueryables, this will return a Lazy collection of entities. The first time that one of the Lazy collections is accessed, all of the pending queries will be batched and executed together.

[Fact]
public void ToFuture()
{
    // SimpleDataContext Implements IFutureDataContext 
    using (var dataContext = new SimpleDataContext())
    {
        Lazy<IList<Person>> people = dataContext.Persons
            .Where(p => p.FirstName == "Tom" || p.FirstName == "Cat")
            .ToFuture();
 
        Lazy<IList<Pet>> pets = dataContext.Pets
            .Where(p => p.Name == "Taboo")
            .ToFuture();
 
        // Single database call!
        Assert.Equal(2, people.Value.Count);
        Assert.Equal(1, pets.Value.Count);
    }
}

To see the future queries working, you can use SqlProfiler to capture the batch query:

Extending Your DataContext

To use the code above, you need only extend your generated DataContext to implement the IFutureDataContext interface (which consists of a mere one property). Additionally, the sample code below overrides the Dispose method to optimize query disposal.

partial class SimpleDataContext : IFutureDataContext
{
    protected override void Dispose(bool disposing)
    {
        if (_futureCollection != null)
        {
            _futureCollection.Dispose();
            _futureCollection = null;
        }
 
        base.Dispose(disposing);
    }
 
    private IFutureCollection _futureCollection;
    public IFutureCollection FutureCollection
    {
        get
        {
            if (_futureCollection == null)
                _futureCollection = this.CreateFutureCollection();
 
            return _futureCollection;
        }
    }
}

Do you not have access to extend your DataContext? No problem...

Alternative Consumption

Your DataContext does not need to implement IFutureDataContext to use future queries. You can also create a FutureCollection and pass that into the ToFuture method. This will provide the future queries with a batch context.

[Fact]
public void FutureCollection()
{
    using (var dataContext = new SimpleDataContext())
    using (var futureCollcetion = dataContext.CreateFutureCollection())
    {
        Lazy<IList<Person>> people = dataContext.Persons
            .Where(p => p.FirstName == "Tom" || p.FirstName == "Cat")
            .ToFuture(futureCollcetion);
 
        Lazy<IList<Pet>> pets = dataContext.Pets
            .Where(p => p.Name == "Taboo")
            .ToFuture(futureCollcetion);
 
        // Single database call!
        Assert.Equal(2, people.Value.Count);
        Assert.Equal(1, pets.Value.Count);
    }
}

Links

If you enjoy the future queries or need to extend them, then please feel free to download the source from GitHub.

LinqToSql.Futures on GitHub
LinqToSql.Futures on NuGet

Shout it

Enjoy,
Tom

Real Time Web Analytics