如何在 运行 核心中 运行 存储过程?

How to run stored procedures in Entity Framework Core?

我在 ASP.NET 核心应用程序中使用 EF Core 1.0。你能告诉我执行存储过程的正确方法吗? ObjectParameters((IObjectContextAdapter)this).ObjectContext.ExecuteFunction 的旧方法不起作用。

存储过程支持尚未在 EF7 中实现(截至 7.0.0-beta3)。您可以使用问题 #245.

跟踪此功能的进度

现在,您可以使用 ADO.NET.

的老式方法来完成
var connection = (SqlConnection)context.Database.AsSqlServer().Connection.DbConnection;

var command = connection.CreateCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "MySproc";
command.Parameters.AddWithValue("@MyParameter", 42);

command.ExecuteNonQuery();

"(SqlConnection)context" -- 这种类型转换不再有效。你可以这样做:"SqlConnection context;

".AsSqlServer()" -- 不存在。

"command.ExecuteNonQuery();" -- 没有 return 结果。 reader=command.ExecuteReader() 确实有效。

使用 dt.load(reader)... 然后您必须将框架从 5.0 切换回 4.51,因为 5.0 尚不支持 datatables/datasets。注:这是VS2015 RC.

EF Core 1.0 中对存储过程的支持现已解决,这也支持多个结果集的映射。

Check here for the fix details

你可以在c#中这样调用它

var userType = dbContext.Set().FromSql("dbo.SomeSproc @Id = {0}, @Name = {1}", 45, "Ada");

我在ExecuteSqlCommandExecuteSqlCommandAsync上遇到了很多麻烦,IN参数很容易,但是OUT参数很难。

我不得不像这样恢复使用 DbCommand -

DbCommand cmd = _context.Database.GetDbConnection().CreateCommand();

cmd.CommandText = "dbo.sp_DoSomething";
cmd.CommandType = CommandType.StoredProcedure;

cmd.Parameters.Add(new SqlParameter("@firstName", SqlDbType.VarChar) { Value = "Steve" });
cmd.Parameters.Add(new SqlParameter("@lastName", SqlDbType.VarChar) { Value = "Smith" });

cmd.Parameters.Add(new SqlParameter("@id", SqlDbType.BigInt) { Direction = ParameterDirection.Output });

我在 this post 中写了更多关于它的内容。

目前EF 7或EF Core不支持在设计器中导入存储过程并直接调用的旧方法。您可以查看路线图以了解未来将支持的内容: EF core roadmap.

所以现在最好使用 SqlConnection 来调用存储过程或任何原始查询,因为您不需要整个 EF 来完成这项工作。这里有两个例子:

调用return单个值的存储过程。在本例中为字符串。

CREATE PROCEDURE [dbo].[Test]
    @UserName nvarchar(50)
AS
BEGIN
    SELECT 'Name is: '+@UserName;
END

调用return一个列表的存储过程。

CREATE PROCEDURE [dbo].[TestList]
AS
BEGIN
    SELECT [UserName], [Id] FROM [dbo].[AspNetUsers]
END

要调用这些存储过程,最好创建包含所有这些函数的静态 class,例如,我将其称为 DataAccess class,如下所示:

public static class DataAccess

    {
        private static string connectionString = ""; //Your connection string
        public static string Test(String userName)
        {
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                conn.Open();

                // 1.  create a command object identifying the stored procedure
                SqlCommand cmd = new SqlCommand("dbo.Test", conn);

                // 2. set the command object so it knows to execute a stored procedure
                cmd.CommandType = CommandType.StoredProcedure;

                // 3. add parameter to command, which will be passed to the stored procedure
                cmd.Parameters.Add(new SqlParameter("@UserName", userName));

                // execute the command
                using (var rdr = cmd.ExecuteReader())
                {
                    if (rdr.Read())
                    {
                        return rdr[0].ToString();
                    }
                    else
                    {
                        return null;
                    }
                }
            }
        }

        public static IList<Users> TestList()
        {
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                conn.Open();

                // 1.  create a command object identifying the stored procedure
                SqlCommand cmd = new SqlCommand("dbo.TestList", conn);

                // 2. set the command object so it knows to execute a stored procedure
                cmd.CommandType = CommandType.StoredProcedure;

                // execute the command
                using (var rdr = cmd.ExecuteReader())
                {
                    IList<Users> result = new List<Users>();
                    //3. Loop through rows
                    while (rdr.Read())
                    {
                        //Get each column
                        result.Add(new Users() { UserName = (string)rdr.GetString(0), Id = rdr.GetString(1) });
                    }
                    return result;
                }
            }

        }
    }

而用户 class 是这样的:

public class Users
{
     public string UserName { set; get; }
     public string Id { set; get; }
}

顺便说一句,您无需担心为 sql 的每个请求打开和关闭连接的性能,因为 asp.net 正在为您管理这些。 我希望这对您有所帮助。

要执行存储过程,请使用执行 RAW SQL 查询的 FromSql 方法

例如

    var products= context.Products
        .FromSql("EXECUTE dbo.GetProducts")
        .ToList();

与参数一起使用

    var productCategory= "Electronics";

    var product = context.Products
        .FromSql("EXECUTE dbo.GetProductByCategory {0}", productCategory)
        .ToList();

    var productCategory= new SqlParameter("productCategory", "Electronics");

    var product = context.Product
        .FromSql("EXECUTE dbo.GetProductByName  @productCategory", productCategory)
        .ToList();

执行 RAW SQL 查询或存储过程存在某些限制。您不能将它用于 INSERT/UPDATE/DELETE。如果要执行 INSERT、UPDATE、DELETE 查询,请使用 ExecuteSqlCommand

    var categoryName = "Electronics";
    dataContext.Database
               .ExecuteSqlCommand("dbo.InsertCategory @p0", categoryName);

EF Core 对存储过程的支持与早期版本的 EF Code 相似。

您需要通过从 EF 继承 DbContext class 来创建 DbContext class。存储过程正在使用 DbContext 执行。

第一步是编写一个从 DbContext 创建 DbCommand 的方法。

public static DbCommand LoadStoredProc(
  this DbContext context, string storedProcName)
{
  var cmd = context.Database.GetDbConnection().CreateCommand();
  cmd.CommandText = storedProcName;
  cmd.CommandType = System.Data.CommandType.StoredProcedure;
  return cmd;
}

要将参数传递给存储过程,请使用以下方法。

public static DbCommand WithSqlParam(
  this DbCommand cmd, string paramName, object paramValue)
{
  if (string.IsNullOrEmpty(cmd.CommandText))
    throw new InvalidOperationException(
      "Call LoadStoredProc before using this method");
  var param = cmd.CreateParameter();
  param.ParameterName = paramName;
  param.Value = paramValue;
  cmd.Parameters.Add(param);
  return cmd;
}

最后使用 MapToList 方法将结果映射到自定义对象列表。

private static List<T> MapToList<T>(this DbDataReader dr)
{
  var objList = new List<T>();
  var props = typeof(T).GetRuntimeProperties();

  var colMapping = dr.GetColumnSchema()
    .Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower()))
    .ToDictionary(key => key.ColumnName.ToLower());

  if (dr.HasRows)
  {
    while (dr.Read())
    {
      T obj = Activator.CreateInstance<T>();
      foreach (var prop in props)
      {
        var val = 
          dr.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value);
          prop.SetValue(obj, val == DBNull.Value ? null : val);
      }
      objList.Add(obj);
    }
  }
  return objList;
}

现在我们准备好使用ExecuteStoredProc方法执行存储过程并将其映射到类型为T的列表。

public static async Task<List<T>> ExecuteStoredProc<T>(this DbCommand command)
{
  using (command)
  {
    if (command.Connection.State == System.Data.ConnectionState.Closed)
    command.Connection.Open();
    try
    {
      using (var reader = await command.ExecuteReaderAsync())
      {
        return reader.MapToList<T>();
      }
    }
    catch(Exception e)
    {
      throw (e);
    }
    finally
    {
      command.Connection.Close();
    }
  }
}

例如,要执行一个名为“StoredProcedureName”的存储过程,带有两个参数“firstparamname”和“secondparamname”,这就是实现。

List<MyType> myTypeList = new List<MyType>();
using(var context = new MyDbContext())
{
  myTypeList = context.LoadStoredProc("StoredProcedureName")
  .WithSqlParam("firstparamname", firstParamValue)
  .WithSqlParam("secondparamname", secondParamValue).
  .ExecureStoredProc<MyType>();
}

如果您使用 EntityFrameworkCore 从 Informix 执行存储过程,则需要包含命令 EXECUTE PROCEDURE

var spresult = _informixContext.procdata.FromSql("EXECUTE PROCEDURE dummyproc ({0},{1},{2})", parameters: new[] { p0, p1,p2 }).ToList();

使用 MySQL 连接器和 Entity Framework Core 2.0

我的问题是我遇到了类似 fx 的异常。 Ex.Message = "The required column 'body' was not present in the results of a 'FromSql' operation."。因此,为了以这种方式通过存储过程获取行,您必须 return 与 DBSet 相关联的实体类型的所有列,即使您不需要为当前访问所有列要求。

var result = _context.DBSetName.FromSql($"call storedProcedureName()").ToList(); 

或带参数

var result = _context.DBSetName.FromSql($"call storedProcedureName({optionalParam1})").ToList(); 

无需执行任何操作...当您为代码优先方法初始化创建 dbcontext 时 fluent API 区域下方的命名空间制作 sp 列表并将其用于您想要的其他地方。

public partial class JobScheduleSmsEntities : DbContext
{
    public JobScheduleSmsEntities()
        : base("name=JobScheduleSmsEntities")
    {
        Database.SetInitializer<JobScheduleSmsEntities>(new CreateDatabaseIfNotExists<JobScheduleSmsEntities>());
    }

    public virtual DbSet<Customer> Customers { get; set; }
    public virtual DbSet<ReachargeDetail> ReachargeDetails { get; set; }
    public virtual DbSet<RoleMaster> RoleMasters { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //modelBuilder.Types().Configure(t => t.MapToStoredProcedures());

        //modelBuilder.Entity<RoleMaster>()
        //     .HasMany(e => e.Customers)
        //     .WithRequired(e => e.RoleMaster)
        //     .HasForeignKey(e => e.RoleID)
        //     .WillCascadeOnDelete(false);
    }
    public virtual List<Sp_CustomerDetails02> Sp_CustomerDetails()
    {
        //return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Sp_CustomerDetails02>("Sp_CustomerDetails");
        //  this.Database.SqlQuery<Sp_CustomerDetails02>("Sp_CustomerDetails");
        using (JobScheduleSmsEntities db = new JobScheduleSmsEntities())
        {
           return db.Database.SqlQuery<Sp_CustomerDetails02>("Sp_CustomerDetails").ToList();

        }

    }

}

}

public partial class Sp_CustomerDetails02
{
    public long? ID { get; set; }
    public string Name { get; set; }
    public string CustomerID { get; set; }
    public long? CustID { get; set; }
    public long? Customer_ID { get; set; }
    public decimal? Amount { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    public int? CountDay { get; set; }
    public int? EndDateCountDay { get; set; }
    public DateTime? RenewDate { get; set; }
    public bool? IsSMS { get; set; }
    public bool? IsActive { get; set; }
    public string Contact { get; set; }
}

我发现这个扩展非常有用:StoredProcedureEFCore

那么用法就是这样

List<Model> rows = null;

ctx.LoadStoredProc("dbo.ListAll")
   .AddParam("limit", 300L)
   .AddParam("limitOut", out IOutParam<long> limitOut)
   .Exec(r => rows = r.ToList<Model>());

long limitOutValue = limitOut.Value;

ctx.LoadStoredProc("dbo.ReturnBoolean")
   .AddParam("boolean_to_return", true)
   .ReturnValue(out IOutParam<bool> retParam)
   .ExecNonQuery();

bool b = retParam.Value;

ctx.LoadStoredProc("dbo.ListAll")
   .AddParam("limit", 1L)
   .ExecScalar(out long l);

我尝试了所有其他解决方案,但都不适合我。但我找到了一个合适的解决方案,这可能对这里的人有帮助。

要调用存储过程并将结果放入 EF Core 中的模型列表中,我们必须执行 3 个步骤。

步骤 1. 您需要添加一个新的 class,就像您的实体 class 一样。哪个应该具有 SP 中所有列的属性。例如,如果您的 SP 返回两个名为 IdName 的列,那么您的新 class 应该类似于

public class MySPModel
{
    public int Id {get; set;}
    public string Name {get; set;}
}

步骤 2.

然后您必须为您的 SP 添加一个 DbQuery 属性 到您的 DBContext class。

public partial class Sonar_Health_AppointmentsContext : DbContext
{
        public virtual DbSet<Booking> Booking { get; set; } // your existing DbSets
        ...

        public virtual DbQuery<MySPModel> MySP { get; set; } // your new DbQuery
        ...
}

步骤 3.

现在您将能够从您的 DBContext 中调用并从您的 SP 获取结果。

var result = await _context.Query<MySPModel>().AsNoTracking().FromSql(string.Format("EXEC {0} {1}", functionName, parameter)).ToListAsync();

我正在使用通用的 UnitOfWork 和存储库。所以我执行 SP 的函数是

/// <summary>
/// Execute function. Be extra care when using this function as there is a risk for SQL injection
/// </summary>
public async Task<IEnumerable<T>> ExecuteFuntion<T>(string functionName, string parameter) where T : class
{
    return await _context.Query<T>().AsNoTracking().FromSql(string.Format("EXEC {0} {1}", functionName, parameter)).ToListAsync();
}

希望对大家有所帮助!!!

我正在使用 Entity Framework Core 和我的 ASP.Net Core 3.x WebAPI。我想要我的终点之一只是执行一个特定的存储过程,这是我需要的代码:

namespace MikesBank.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ResetController : ControllerBase
    {
        private readonly MikesBankContext _context;

        public ResetController(MikesBankContext context)
        {
            _context = context;
        }

        [HttpGet]
        public async Task<ActionResult> Get()
        {
            try
            {
                using (DbConnection conn = _context.Database.GetDbConnection())
                {
                    if (conn.State != System.Data.ConnectionState.Open)
                        conn.Open();
                    var cmd = conn.CreateCommand();
                    cmd.CommandText = "Reset_Data";
                    await cmd.ExecuteNonQueryAsync();
                }
                return new OkObjectResult(1);
            }
            catch (Exception ex)
            {
                return new BadRequestObjectResult(ex.Message);
            }
        }
    }
}

请注意我需要如何获取已注入的 DbContext,但我还需要 Open() 此连接。

我们应该在模型中为数据库上下文创建一个 属性,其中 DbQuery 而不是 DbSet...

public class MyContextContext : DbContext
{
    public virtual DbQuery<CheckoutInvoiceModel> CheckoutInvoice { get; set; } 
}

比一个方法后可以用来return结果

public async Task<IEnumerable<CheckoutInvoiceModel>> GetLabReceiptByReceiptNo(string labReceiptNo)
{
    var listing = new List<CheckoutInvoiceModel>();
    try
    {
        var sqlCommand = $@"[dbo].[Checkout_GetLabReceiptByReceiptNo] {labReceiptNo}";
        
        listing = await db.Set<CheckoutInvoiceModel>().FromSqlRaw(sqlCommand).ToListAsync();                       
                        
    }
    catch (Exception ex)
    {
        return null;
    }
    return listing;
}

从上面的例子中,我们可以使用你喜欢的任何一个选项。

希望对您有所帮助!

根据存储过程的 Select 查询中的字段创建特殊的 class。 例如,我将调用此 class ResulData

添加到您的上下文中 EF

modelBuilder.Entity<ResultData>(e =>
        {
            e.HasNoKey();
        });

这是一个使用存储过程获取数据的示例函数

public async Task<IEnumerable<ResultData>> GetDetailsData(int id, string name)
{
    var pId = new SqlParameter("@Id", id);
  var pName = new SqlParameter("@Name", name);
    return await _context.Set<ResultData>()
             .FromSqlRaw("Execute sp_GetDeailsData  @Id @Name", parameters: new[] { pId, pName })
            .ToArrayAsync();
}

我通过 https://github.com/verdie-g/StoredProcedureEFCore,EnterpriseLibrary.Data.NetCore,EFCor.SqlServer,EFCore.Tools

使用了 StoredProcedureEFCore nuget 包

我尝试使用{存储库模式}的 DbFirst 方法..我认为是

startup.cs

ConfigureServices(IServiceCollection services){
    services.AddDbContext<AppDbContext>(opt => opt
                   .UseSqlServer(Configuration.GetConnectionString("SampleConnectionString")));
    services.AddScoped<ISomeDAL, SomeDAL>();

}
            
    public  class AppDbContext : DbContext{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {}
}

ISomeDAl 接口有 {GetPropertiesResponse GetAllPropertiesByCity(int CityId);}

public class SomeDAL : ISomeDAL
{
     private readonly AppDbContext context;

     public SomeDAL(AppDbContext context)
         {
             this.context = context;
         }
     public  GetPropertiesResponse GetAllPropertiesByCity(int CityId)
     {
         //Create Required Objects for response 
         //wont support ref Objects through params
         context.LoadStoredProc(SQL_STATEMENT)
            .AddParam("CityID", CityId).Exec( r =>
             {
                  while (r.Read())
                  {

                       ORMapping<GenericRespStatus> orm = new  ORMapping<GenericRespStatus>();
                       orm.AssignObject(r, _Status);
                  }

                  if (r.NextResult())
                  {

                       while (r.Read())
                       {
                           Property = new Property();
                           ORMapping<Property> orm = new ORMapping<Property>();
                           orm.AssignObject(r, Property);
                           _propertyDetailsResult.Add(Property);
                       }
                  }    
           });
    return new GetPropertiesResponse{Status=_Status,PropertyDetails=_propertyDetailsResult}; 
    }
}

public class GetPropertiesResponse
{
     public GenericRespStatus Status;
     public List<Property> PropertyDetails;
     public GetPropertiesResponse()
         {
             PropertyDetails = new List<Property>();
         }
}
public class GenericRespStatus
{
     public int ResCode { get; set; }
     public string ResMsg { get; set; }
}
internal class ORMapping<T>
{
    public void AssignObject(IDataReader record, T myClass)
    {
        PropertyInfo[] propertyInfos = typeof(T).GetProperties();
        for (int i = 0; i < record.FieldCount; i++)
        {
            if (propertyInfos.Any(obj => obj.Name == record.GetName(i))) //&& record.GetValue(i) != DBNull.Value
            {
                propertyInfos.Single(obj => obj.Name == record.GetName(i)).SetValue(myClass, Convert.ChangeType(record.GetValue(i), record.GetFieldType(i)));
            }
        }
    }
}

由于我的团队同意我们将使用通用 UnitOfWork 模式,因此我在创建我的解决方案时采用了一些每个人的解决方案。

我也发布了一些 UnitOfWork 代码,这样您就可以了解为什么我需要这样实现它。

public interface IUnitOfWork : IDisposable
{
    DbContext Context { get; }
    Task<List<T>> ExecuteStoredProc<T>(string storedProcName, Dictionary<string, object> procParams) where T : class;
}

接口实现:

public class UnitOfWork : IUnitOfWork
{
    public DbContext Context { get; private set; }

/// <summary>
/// Execute procedure from database using it's name and params that is protected from the SQL injection attacks.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="storedProcName">Name of the procedure that should be executed.</param>
/// <param name="procParams">Dictionary of params that procedure takes. </param>
/// <returns>List of objects that are mapped in T type, returned by procedure.</returns>
    public async Task<List<T>> ExecuteStoredProc<T>(string storedProcName, Dictionary<string, object> procParams) where T : class
    {
        DbConnection conn = Context.Database.GetDbConnection();
        try
        {
            if(conn.State != ConnectionState.Open)
                await conn.OpenAsync();

            await using (DbCommand command = conn.CreateCommand())
            {
                command.CommandText = storedProcName;
                command.CommandType = CommandType.StoredProcedure;

                foreach (KeyValuePair<string, object> procParam in procParams)
                {
                    DbParameter param = command.CreateParameter();
                    param.ParameterName = procParam.Key;
                    param.Value = procParam.Value;
                    command.Parameters.Add(param);
                }

                DbDataReader reader = await command.ExecuteReaderAsync();
                List<T> objList = new List<T>();
                IEnumerable<PropertyInfo> props = typeof(T).GetRuntimeProperties();
                Dictionary<string, DbColumn> colMapping = reader.GetColumnSchema()
                    .Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower()))
                    .ToDictionary(key => key.ColumnName.ToLower());

                if (reader.HasRows)
                {
                    while (await reader.ReadAsync())
                    {
                        T obj = Activator.CreateInstance<T>();
                        foreach (PropertyInfo prop in props)
                        {
                            object val =
                                reader.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value);
                            prop.SetValue(obj, val == DBNull.Value ? null : val);
                        }
                        objList.Add(obj);
                    }
                }
                reader.Dispose();

                return objList;
            }
        }
        catch (Exception e)
        {
            System.Diagnostics.Debug.WriteLine(e.Message, e.InnerException);
        }
        finally
        {
            conn.Close();
        }

        return null; // default state
    }

示例用法如下:

public class MyService : IMyService 
{
        private readonly IUnitOfWork _uow;
        public MyService(IUnitOfWork uow)
        {
            _uow = uow;
        }
        
        public async Task<List<TreeViewModel>> GetTreeOptions()
        {
            var procParams = new Dictionary<string, object>()
            {
                {"@Id", 2}
            };
            var result = await _uow.ExecuteStoredProc<TreeViewModel>("FetchTreeProcedure", procParams);
            return result;
        }
}

我正在使用 Entity Framework Core。对存储过程和即席查询的支持不像在 Framework 中那样流畅。

这里有一些例子供以后参考:

根据存储过程的结果填充实体列表:

[dbo].[GetUnarchivedJobs] 存储过程 returns 匹配 Job 实体的记录列表。

我们可以在 Jobs 属性 上使用 FromSqlInterpolated() 方法来调用存储过程并返回 Job 的列表。

NoTracking()用于加速性能,在这种情况下我们不会更新实体。

using Microsoft.EntityFrameworkCore;

public class DbContext : Microsoft.EntityFrameworkCore.DbContext
{
    protected DbSet<Job> Jobs { get; set; }

    // Populate a list of entities from the results of a stored procedure
    public Task<List<Job>> GetUnarchivedJobs(int maxQty, CancellationToken cancellationToken) =>
        Jobs.FromSqlInterpolated($"EXEC [dbo].[GetUnarchivedJobs] @MaxQty = {maxQty}")
            .AsNoTracking()
            .ToListAsync(cancellationToken)
            ;

    public DbContext(DbContextOptions<DbContext> options) : base(options) { }
}

将整数数组发送到存储过程:

[dbo].[SetJobListArchiveFlags] 存储过程有一个类型为 integer_list_tbltype 的参数。

我们需要创建一个 DataTable 来匹配 integer_list_tbltype 类型,它有一个名为 n.

的列

需要将 int 值添加到 DataTable

A SqlParameter 用于将填充的 DataTable 传递给存储过程。

因为我们没有填充任何实体,所以我们需要使用 Database 属性 上的方法来调用存储过程。

using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System.Data;

public class DbContext : Microsoft.EntityFrameworkCore.DbContext
{
    // Send an array of integers to a stored procedure
    public async Task<int> MarkJobsAsArchived(IEnumerable<int> jobIds, CancellationToken cancellationToken)
    {
        // This DataTable matches the `integer_list_tbltype` db type
        var table = new DataTable();
        table.Columns.Add("n", typeof(int));
        foreach (var id in jobIds) table.Rows.Add(id);

        var parameter = new SqlParameter("@jobIds", SqlDbType.Structured);
        parameter.Value = table;
        parameter.TypeName = "integer_list_tbltype";

        var rowsUpdatedCount = await Database.ExecuteSqlRawAsync("EXEC [dbo].[SetJobListArchiveFlags] @jobIds", new[] { parameter }, cancellationToken);
        return rowsUpdatedCount;
    }
}