กลับ Func‹Task› ตรงกลางของการใช้บล็อก

ฉันต้องการคืน Func ตรงกลางของบล็อกที่ใช้งาน ฉันควรกังวลเกี่ยวกับการกำจัดก่อนที่ผู้ใช้จะรันผลลัพธ์ Func หรือไม่

รหัสตัวอย่าง:

private IDbContextTransaction _transaction;

public Func<Task> BeginTransaction()
{
    Task lockDispose = CommitTransaction();
    using (_transaction = _dbContext.Database.BeginTransaction())
    {
        return async() =>
        {
            await lockDispose;
        };
        Task.WaitAll(lockDispose); //This code is unreachable.
    }
}

private async Task CommitTransaction()
{
    _transaction.Commit();
    await Task.CompletedTask;
}

โปรดทราบว่าเวลาดำเนินการของผลลัพธ์ Func ขึ้นอยู่กับผู้ใช้บริการนี้

ฉันตรวจสอบคำถามนี้แล้ว และไม่ใช่คำตอบของฉัน


person FarhadGh    schedule 20.12.2020    source แหล่งที่มา
comment
เมื่อ func ถูกส่งคืน ธุรกรรมจะถูกกำจัดในขณะที่งานภายใน func กำลังทำงานอยู่ นั่นอาจไม่ใช่สิ่งที่คุณต้องการ โดยพิจารณาจากชื่อวิธีการของคุณ? คุณต้องระบุให้ชัดเจนมากขึ้นถึงสิ่งที่คุณพยายามทำให้สำเร็จ   -  person Mo B.    schedule 20.12.2020
comment
ฉันต้องการชะลอการกำจัดจนกว่าผู้ใช้จะตัดสินใจดำเนินการ func ผลลัพธ์   -  person FarhadGh    schedule 20.12.2020
comment
คุณช่วยยกตัวอย่างว่าคุณตั้งใจจะใช้เมธอด BeginTransaction อย่างไร   -  person Theodor Zoulias    schedule 20.12.2020
comment
ฉันต้องการบรรลุเป้าหมายนี้: 1. ไม่มีใครสามารถทำธุรกรรมได้สองครั้ง (ดังนั้นฉันจึงซ่อน CommitTransaction) 2. อย่าบังคับให้ผู้ใช้ใช้โดยใช้บล็อก (หรือใช้บรรทัดเดียว) 3. ผู้ใช้สามารถทำอะไรก็ได้กับ dbContext และบันทึกการเปลี่ยนแปลงหลายครั้งก่อน การทำธุรกรรม __ การใช้งานเริ่มต้นสำหรับกรณีของฉันยังอยู่ในมิดเดิลแวร์ก่อนและหลัง 'รอถัดไป (บริบท);'   -  person FarhadGh    schedule 20.12.2020
comment
แต่ฉันไม่สามารถบรรลุเป้าหมายเหล่านี้ได้ ฉันคืนธุรกรรมจากบริการแล้ว น่าเสียดาย   -  person FarhadGh    schedule 20.12.2020
comment
ฉันไม่คิดว่าการให้ค่าส่งคืนแก่ผู้ใช้ Func<Task> นั้นมีความหมายหรือสะดวก หากคุณไม่ต้องการให้พวกเขาทำธุรกรรมสองครั้ง คุณสามารถให้ส่วนหน้า Transaction ด้วยเมธอด CommitTransaction ที่จะเรียกใช้ Transaction.CommitTransaction พื้นฐานที่แท้จริงได้มากที่สุดหนึ่งครั้ง   -  person Theodor Zoulias    schedule 21.12.2020


คำตอบ (1)


เนื่องจากคุณต้องการให้ผู้ใช้สามารถทำงานกับการเชื่อมต่อระหว่างการโทร BeginTransaction และ CommitTransaction ดังนั้นสิ่งเดียวที่คุณทำได้คือย้ายการกำจัดออกนอกขอบเขตนี้:

private IDbContextTransaction _transaction;

public Func<Task> BeginTransaction()
{
    _transaction = _dbContext.Database.BeginTransaction()
    return CommitTransaction;
}

private async Task CommitTransaction()
{
    _transaction.Commit();
    _transaction.Dispose();
    await Task.CompletedTask;
}

// I advice you implement IDisposable fully, but 
// this will do for the sake of demonstration
public void Dispose()
{
    _transaction?.Dispose();
}

จากนั้นที่ไหนสักแห่งข้างนอก คุณจะต้องทำอะไรบางอย่างตาม:

using (var obj = TheWayYouInitializeYourObject())
{
    var commit = obj.BeginTransaction();
    // DO WORK
    await commit();
}

or

try
{
    var commit = obj.BeginTransaction();
    // DO WORK
    await commit();
}
finally
{
    obj.Dispose();
}

โดยพื้นฐานแล้ว using ของคุณไม่สามารถขยายช่องว่างที่ผู้ใช้ของคุณทำงาน ดังนั้นพวกเขาจะต้องทำด้วยตัวเอง

โดยทั่วไปเป็นความคิดที่ดีที่จะสร้างสิ่งของที่ต้องใช้งานกับของใช้แล้วทิ้งแบบใช้แล้วทิ้งเช่นกัน

person Heagon    schedule 20.12.2020
comment
ฉันสงสัยว่าหลังจากเรียก BeginTransaction() ธุรกรรมจะเริ่มต้นขึ้น และผู้ใช้จะต้องทำงานกับ dbContext หลังจากนั้น ฉันจะทดสอบวิธีแก้ปัญหาของคุณและจะกลับมาอีกครั้งเพื่ออัปเดตความคิดเห็นนี้ - person FarhadGh; 20.12.2020
comment
@FarhadGh อัปเดตคำตอบ - person Heagon; 20.12.2020