DBContext扩展方法,线程安全

本文关键字:线程 安全 方法 扩展 DBContext | 更新日期: 2023-09-27 18:04:51

我有一个DBContext helper类,它使用扩展方法:

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);
    }
}

扩展方法是否不适合这个,因为它们可能被不同的线程访问导致问题?

DBContext扩展方法,线程安全

扩展方法可能是线程安全的,也可能是线程不安全的,这取决于你如何编写它们。

当每个DbContext从不同的线程访问时,您的方法是线程安全的。这是合理的限制,因为DbContext不是真正的线程安全类。(启用多个活动结果集,您可以删除此限制,但这不是一个好的决定,因为DbContext跟踪数据)。

为单个业务操作创建DbContext并立即处置是很好的实践——这是工作单元模式的方式。

初版在Web API场景中,您可以为每个HTTP请求创建不同的DbContext,甚至可以为每个操作创建不同的上下文:

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);
        }
    }
}

方法FindAsync在此代码中正常工作,尽管它不方便调用。我将更改签名:

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);
        }
    }
}