выполнить хранимую процедуру внутри транзакции Entity Framework - PullRequest
0 голосов
/ 01 октября 2019

У меня проблема при выполнении хранимой процедуры внутри открытой транзакции в Entity Framework.

Проблема в том, что (посмотрите на код), когда я выполняю хранимую процедуру p_RecalcCost, возвращаемое значение верное,но значение в базе данных не изменится.

Это позволяет мне думать, что операция обновления, выполненная в хранимой процедуре, находится за пределами моей транзакции.

Есть идеи?

public bool myMethod(Entities ctx=null)
{
   bool ok = true;
   var context = ctx == null ? new Entities() : ctx;
   var dbTran = context.Database.CurrentTransaction ?? context.Database.BeginTransaction();
   List<MyObject> rows= MyObject.getRows(id, context);

   foreach (MyObject ier in rows)
   {
       MyObject oldObj = MyObject.GetEntity(ier.ID,context);
       decimal oldCost =  oldObj.Cost;


       System.Data.Entity.Core.Objects.ObjectParameter myOutputParamDecimal = new System.Data.Entity.Core.Objects.ObjectParameter("CostRes", typeof(decimal));
      context.p_RecalcProductCost(ier.ID, myOutputParamDecimal);

      context.SaveChanges();
      decimal newCost = Convert.ToDecimal(myOutputParamDecimal.Value); 


   }

  ....ok is always true
 if (ctx == null)
 {
    if (ok)
        dbTran.Commit();
    else
        dbTran.Rollback();

    context.Dispose();
  }

  return ok;
}

Здесь код хранимой процедуры

CREATE PROCEDURE [dbo].[p_RecalcProductCost]
@ID_Product int null,
@CostRes decimal(10,2) OUTPUT

AS
BEGIN

SET NOCOUNT ON;
SET FMTONLY OFF;

SELECT TOP 1 @CostRes=100 --is an example, this is a result of operations

--update cost on table Product
UPDATE Product set Cost = @CostRes
WHERE (@ID_Product IS NULL OR (@ID_Product is not null AND ID_Product = @ID_Product))

--update cost on another table
UPDATE ProductSupplier 
SET ps.Cost = CostRes   
WHERE
(@ID_Product IS NULL OR (@ID_Product is not null AND ps.ID_Product = @ID_Product)) 

END

Если в DEBUG после сохраненного выполнения я делаю выборку в БД с УРОВНЕМ ИЗОЛЯЦИИ СДЕЛОК СЧИТЫВАНИЯ, ЧТО НЕОБХОДИМО, Стоимость равна 100, но когда транзакциязаканчивается стоимость на БД равна NULL.

Ответы [ 2 ]

1 голос
/ 01 октября 2019

Существует несколько проблем, связанных с временем существования контекста / областью действия и временем жизни перехода.

Скорее всего, проблема заключается в том, что вы не commit transaction, поэтому он будет откатан.

Выражения типа

var context = ctx == null ? new Entities() : ctx;

и

var dbTran = context.Database.CurrentTransaction ?? context.Database.BeginTransaction();

представляют проблему, поскольку они показывают, что вы понятия не имеете, кому принадлежит соединение / транзакция, поэтому вам придется предоставить кодчтобы справиться с этим.

Попробуйте использовать операторы одним способом, которым вы могли бы справиться с этим:

public bool myMethod()
{
    if (ctx == null)
    {
        using (ctx = new Entities())
        {
            using (var dbTran = ctx.Database.BeginTransaction())
            {
                Update(ctx); // you need to return the values here
                dbTran.Commit();
            }
        }
    }
    else
    {
        if (ctx.Database.CurrentTransaction == null)
        {
            using (var dbTran = ctx.Database.BeginTransaction())
            {
                Update(ctx); // you need to return the values here
                dbTran.Commit();
            }
        }
        else
        {
            Update(ctx); // you need to return the values here
        }
    }
}

private void Update(DbContext context)
{
    List<MyObject> rows = MyObject.getRows(id, context);

    foreach (MyObject ier in rows)
    {
        MyObject oldObj = MyObject.GetEntity(ier.ID, context);
        List<p_Result> res = context.p_RecalcCost(ier.ID).ToList<p_Result>();
        decimal oldCost = oldObj.Cost;
        decimal newCost = (decimal) res[0].Cost;
    }
}
0 голосов
/ 09 октября 2019

Проблема была не в использовании, потому что я удаляю контекст в конце метода.

 Product p= Product.GetEntity(ier.ID, context);
 context.Entry(updProduct).Reload();
...