简体   繁体   中英

System.ObjectDisposedException: Cannot access a disposed object

I have the following GenericRepository:-

    public class GenericRepository<T> : IGenericRepository<T> where T : class
    {
    public readonly SportsStore2Context Context;
    protected DbSet<T> DbSet;

    public GenericRepository(SportsStore2Context context)
    {
        Context = context;
        DbSet = context.Set<T>();
    }

    public async Task<T> Get<TKey>(Expression<Func<T, bool>> filter = null, string includeProperties = "")

    {
        IQueryable<T> query = Context.Set<T>();
        query = IncludePropertiesQuery(query, includeProperties);

        if (filter != null)
        {
            query = query.Where(filter);
        }

        return await query.SingleOrDefaultAsync();
    }

    public async Task<List<T>> GetAll(Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "")
    {
        IQueryable<T> query = Context.Set<T>();
        query = IncludePropertiesQuery(query, includeProperties);

        if (orderBy != null)
        {
            query = orderBy(query);
        }

        var collection = await query.ToListAsync();
        return collection;
    }

    public async Task Add(T entity, Expression<Func<T, bool>> filter = null)
    {
        var existing = await Get<T>(filter);

        if (existing == null)
        {
            Context.Set<T>().Add(entity);
            Save();
        }

    }


    public void Update(T entity)
    {

        Context.Set<T>().Update(entity);
        Save();
    }

    public void Delete(T entity)
    {
        var dbSet = Context.Set<T>();
        if (Context.Entry(entity).State == EntityState.Detached)
        {
            dbSet.Attach(entity);
        }
        dbSet.Remove(entity);

        Save();
    }

    private void Save()
    {
        try
        {
            Context.SaveChanges();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }

    private IQueryable<T> IncludePropertiesQuery(IQueryable<T> query, string includeProperties = "")
    {
        includeProperties = includeProperties.Trim() ?? string.Empty;
        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        return query;

    }

}

The Get and GetAll work fine, however when I try to Add something to the database, I am getting a "System.ObjectDisposedException: Cannot access a disposed object" error.

I have declared the repository as follows in the Configure of the Startup:-

   services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));

What could be the problem? Am I declaring the context erroneously?

Thanks for your help and time.

UPDATE

Removing the await(async) does work correctly

    public void Add(T entity, Expression<Func<T, bool>> filter = null)
    {
        var existing = Get<T>(filter);
        if (existing.Result != null) return;
        Context.Add(entity);
        Save();
    }

Is this correct?

(I don't know this particular class but this is general advice for mixing async and non-async code)

There's a good reason why it's recommended that async functions follow the naming pattern MyFuncAsync, and that's because it makes it easy to see when you try to call an async function from a non-async one.

Pulling this out from your comments, this is how you call Add

public bool Add(T entity, Expression<Func<T, bool>> filter = null)
{
    try
    {
        genericRepository.Add(entity, filter);
    }
    catch (Exception e)
    {
       return false;
    }
    return true;
}

But you're calling an async function here from an non-async one (which would be more obvious if the function was called AddAsync), which will cause issues unless you block the non-async function like this:

public bool Add(T entity, Expression<Func<T, bool>> filter = null)
{
    try
    {
        genericRepository.Add(entity, filter).Wait();
    }
    catch (Exception e)
    {
       return false;
    }
    return true;
}

It's better if it's async all the way, as this thread will block while the the operation completes, but this should work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM