NickStrupat / EntityFramework.Triggers

Adds events for entity inserting, inserted, updating, updated, deleting, and deleted
MIT License
373 stars 46 forks source link

Cannot access a disposed object #22

Closed fiyazbinhasan closed 6 years ago

fiyazbinhasan commented 6 years ago

I'm getting this error where it's telling me that my context is already disposed so I cant access it anymore. I've this trigger implemented in my Order.cs class, which basically updates the order status,

static Order()
{
    Triggers<Bill>.Inserted += async e =>
    {
        await PaymentStatusChangeNotifierAsync(e);
    };
}

Following is the PaymentStatusChangeNotifierAsync code,

private static async Task<int> PaymentStatusChangeNotifierAsync(IEntry<Bill, Microsoft.EntityFrameworkCore.DbContext> e)
{
    Task.Factory.StartNew(() =>
    {
        var orderedItems = e.Context.Entry(e.Entity.Order)
                                .Collection(o => o.OrderItems).Query()
                                .Where(wi => wi.OrderId == e.Entity.OrderId);

        var paidAmountSumation = e.Entity.Order.Bills.Sum(b => b.PaidAmount);

        var orderedItemAmountSumation = orderedItems.Sum(oi => oi.Quantity * (oi.UnitPrice - oi.Discount));

        if (paidAmountSumation == 0)
            e.Entity.Order.PaymentStatus = PaymentStatus.Unpaid;
        else if (paidAmountSumation == orderedItemAmountSumation)
            e.Entity.Order.PaymentStatus = PaymentStatus.Paid;
        else
            e.Entity.Order.PaymentStatus = PaymentStatus.PartialPaid;
    }).Wait();

    return await e.Context.SaveChangesAsync();
}

The await PaymentStatusChangeNotifierAsync(e); occasionally gives me the following exception.

Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application.

Is there any problems with my trigger implementation?

NickStrupat commented 6 years ago

Hi Fiyaz!

The issue is that your trigger handler is asynchronous and at the moment this library does not support that.

Also, I'm curious why you're creating a new Task inside your asynchronous handler?

You get the error sometimes because the context is disposed after it is used, but your handler may still be trying to run in some other thread. Since your handler makes use of the e.Context object, it may or may not be disposed by the time your handler code runs. Basically this is thread-unsafe.

Some simple fixes are:

Cheers.

fiyazbinhasan commented 6 years ago

I think i get the idea. Sorry I left the Task.Factory.StartNew in the code. Actually I was trying different things to get rid of that problem. But now I know that the handlers can't be asynchronous! Thanks @NickStrupat đź‘Ť