dagda1
dagda1

Reputation: 28760

EF6 DBContext extension methods, thread safe

I have a DBContext helper class that uses extension methods:

public static class DBContextHelper
{
    public static async Task<T> FindAsync<T>(
        this DBContext context, 
        Expression<Func<T, bool>> match) 
        where T : BaseEntity
    {
        return await context.Set<T>().SingleOrDefaultAsync(match);
    }
}

Are extension methods a bad fit for this as they might be accessed by different threads causing problems?

Upvotes: 1

Views: 1312

Answers (1)

Mark Shevchenko
Mark Shevchenko

Reputation: 8197

Extensions methods may be thread safe, and may be thread unsafe depending how you write them.

Your method is thread safe while each DbContext is accessed from different thread. This is reasonable restriction, cause DbContext is not really thread-safe class. (Enabling Multiple Active Result Sets you can remove this restriction, but it's not good decision cause DbContext tracks data).

It's good practice to create DbContext for a single business operation and immediately dispose it — it's the way of the Unit Of Work pattern.

F.e. in Web API scenario you can create different DbContext for each HTTP request or even you can create different context for each operation:

public class UserRepository : IUserRepository
{
    public User async GetByIdAsync(int id)
    {
        using (var dbContext = new MyDbContext())
        {
            var data = await dbContext.FindAsync((UserData user) => user.Id == id);

            return new User(data);
        }
    }
}

The method FindAsync works correctly in this code, although it is not convenient to call. I would change the signature:

public static class DBSetHelper
{
    public static async Task<T> FindAsync<T>(
        this DbSet<T> set, 
        Expression<Func<T, bool>> match) 
        where T : BaseEntity
    {
        return await set.SingleOrDefaultAsync(match);
    }
}

. . .

public class UserRepository : IUserRepository
{
    public User async GetByIdAsync(int id)
    {
        using (var dbContext = new MyDbContext())
        {
            var data = await dbContext.Users.FindAsync(user => user.Id == id);

            return new User(data);
        }
    }
}

Upvotes: 1

Related Questions