How to write a share method for entity framework

Viewed 86

Here is my source code

    public object Index2()
    {
        List<Product> products;
        using (var dbContext = new MarketContext())
        {
            products = dbContext.Products.Select(x => x).ToList();
        }
        return products;
    }

    public object Index3()
    {
        List<Category> categories;
        using (var dbContext = new MarketContext())
        {
            categories = dbContext.Categories.Select(x => x).ToList();
        }
        return categories;
    }

And i want to make a method to reuse "using dbContext"

but i have no idea how to do this

here is my trying code

    public object Index3()
    {
        var sql = ****.Category.Select(x => x);
        var categories = Query<Category>(sql);
        return categories;
    }
    public static List<T> Query<T>(IQueryable<T> sql)
    {
        using (var dbContext = new MarketContext())
        {
            var result = ******sql.ToList();
            return result;
        }
    }

I really want know how to achieve this and is it possible?

Thanks for help

3 Answers

What I understood from your question is, you want to remove duplicate code and refactor into a single function. It's a good practice and will make your code clean.

But to reduce duplicate in your case, you can simply use dependency injection. Inject object of your DbContext and use it inside your functions

public class YourClassName
{
    private static MarketContext _marketDbContext;
    public YourClassName(MarketContext marketDbContext) // DI at constructor
    {
        _marketDbContext = marketDbContext;
    }

    public object Index2()
    {        
        return _marketDbContext.Products.Select(x => x).ToList();
    }

    public object Index3()
    {    
        return dbContext.Categories.Select(x => x).ToList();
    }
}

i want to make a method to reuse "using dbContext"

Unfortunately, a using makes it very difficult to abstract away the context creation.

There is no real way to avoid this. You can't implicitly infer the "using context" behavior on a given method of a given class. It requires your methods to explicitly state that they are using (and thus disposing of) a context.

The closest solutions would be:

  • You can abstract away the instantiation of a new context but keep the using in your method, i.e. using (var db = createDbContext()) { ... }
  • Break up your repository class into query objects (= one-method repositories, sort of), and rely on DI frameworks to inject the context for you. Disposing is done by the DI framework. This works well in a web context (as objects are disposed of after a single web request) but works less elegantly in an always-on application (e.g. Windows Service) as objects are kept in memory indefinitely (for the runtime of the application) unless you manually dispose of them, which is the exact thing you're trying to avoid.
  • It's not impossible to do the above but while keeping the (multi-method) repositories, provided that repeated usage of the same context in the repository does not cause a problem. There are fringe cases that may apply here.
  • If you e.g. encapsulate your context in another object, then you essentially have to create/dispose this new intermediary object in the same way as you're doing for the context right now, which means you've added a layer without solving the actual problem.
  • There are roundabout ways to pass a Func<> or Action<> to a lower level function which automatically creates the context, performs the action and disposes of the context. However, calling this method requires the same level of nesting and complexity that the original using blocks did, so it doesn't actually improve anything.

Other than the first bullet point, these solutions tend to add more complexity than they solve, which makes them a net negative for development value. I understand the desire for trying to improve this, and it intuitively feels like it should be possible, but I've looked and I haven't found a way that's less complex than the initial situation.

I think this is one of those developer pitfalls, best summarized by Jeff Goldblum in Jurassic Park:

Your scientists were so preoccupied with whether or not they could, they didn't stop to think if they should.

You could use a Singleton?

public MyDbContext : DbContext
{

    public static MyDbContext Instance {get; private set;}
}

and use it like MyDbContext.Instance.Category.Select(x => x)?

Related