Заполнить свойства объекта из нескольких SQL выбирает асинхронно C # - PullRequest
0 голосов
/ 20 июня 2019

У меня есть объект с несколькими свойствами, каждое из которых заполняется отдельным оператором выбора SQL.Я хочу выполнить операторы выбора одновременно, но жду возвращения всего объекта, пока каждое свойство не будет иметь данных.Я очень новичок в асинхронности в C #, и мне трудно обдумать это.Это пример того, как я бы сделал это синхронно.

public MyObj GetMyObj()
{
    MyObj obj = new MyObj();

    using (SqlConnection con = new SqlConnection("connectionString"))
    {
        con.Open();

        using (SqlCommand cmd = new SqlCommand())
        {
            cmd.Connection = con;
            cmd.CommandText = "Select ...";
            cmd.CommandType = CommandType.Text;

            obj.Prop1 = cmd.ExecuteScalar();
        }
    }

    using (SqlConnection con = new SqlConnection("connectionString"))
    {
        con.Open();

        using (SqlCommand cmd = new SqlCommand())
        {
            cmd.Connection = con;
            cmd.CommandText = "Select ...";
            cmd.CommandType = CommandType.Text;

            obj.Prop2 = cmd.ExecuteScalar();
        }
    }

    return obj;
}

В идеале я хотел бы создать методы задачи для каждого из этих блоков выбора и подождать, пока полный объект не будет возвращен после завершения (мое базовое понимание взято из статьи Microsoft Async ):

public MyObj GetMyObj()
{
    MyObj obj = new MyObj();

    var prop1Task = GetProp1();
    var prop2Task = GetProp2();

    var allTasks = new List<Task>{prop1Task, prop2Task};
    while (allTasks.Any())
    {
        Task finished = await Task.WhenAny(allTasks);
        if (finished == prop1Task)
        {
            allTasks.Remove(prop1Task);
            obj.Prop1 = await prop1Task;
        } else if (finished == prop2Task)
        {
            allTasks.Remove(prop2Task);
            obj.Prop2 = await prop2Task;
        } else
                allTasks.Remove(finished);
    }

    return obj;
}

private async Task<int> GetProp1()
{
    int prop1 = 0;
    using (SqlConnection con = new SqlConnection("connectionString"))
    {
        con.Open();

        using (SqlCommand cmd = new SqlCommand())
        {
            cmd.Connection = con;
            cmd.CommandText = "Select ...";
            cmd.CommandType = CommandType.Text;

            prop1 = cmd.ExecuteScalar();
        }
    }

    return prop1;
}

При создании метода GetProp1() я получаю предупреждение intellisense, что « В этом асинхронном методе отсутствуют операторы« ожидания »и он будет работать синхронно ».

AmЯ правильно выполняю отдельные методы GetProp?Является ли интеллектуальное предупреждение неправильным?Я выполняю несколько операторов select, поэтому изменение этой операции на асинхронный запуск значительно повысит производительность.

Заранее спасибо за любую помощь!

1 Ответ

1 голос
/ 20 июня 2019

Ничего не выполняется асинхронно в GetProp1.Предупреждение означает именно то, что оно говорит;есть метод, помеченный как async, который ничего не делает асинхронно, поэтому он будет выполняться синхронно.Перепишите ваши GetPropX методы, чтобы использовать асинхронные методы для SqlConnection / SqlCommand.

private async Task<int> GetProp1()
{
    int prop1 = 0;
    using (SqlConnection con = new SqlConnection("connectionString"))
    {
        await con.OpenAsync();

        using (SqlCommand cmd = new SqlCommand())
        {
            cmd.Connection = con;
            cmd.CommandText = "Select ...";
            cmd.CommandType = CommandType.Text;

            prop1 = await cmd.ExecuteScalarAsync();
        }
    }

    return prop1;
}

Тем не менее, если все операторы select выполняются для одной и той же базы данных, вы можете просто выполнить несколькооператоры сразу, используйте ExecuteReader и NextResult.

Примерно так ...

private async Task<MyObj> GetMyObjAsync()
{
   MyObj obj = new MyObj();
   using (SqlConnection con = new SqlConnection("connectionString"))
   {
      await con.OpenAsync();
      string sqlStatements = @"
SELECT Prop1 FROM Table1;
SELECT Prop2 FROM Table2;
SELECT Prop3 FROM Table3;
--etc";

      using (SqlCommand cmd = new SqlCommand(sqlStatements, con))
      using (SqlDataReader reader = await cmd.ExecuteReaderAsync())
      {
         if (await reader.ReadAsync()) 
         {
            obj.Prop1 = Convert.ToInt32(reader["Prop1"]);
         }
         await reader.NextResultAsync();
         if (await reader.ReadAsync()) 
         {
            obj.Prop2 = Convert.ToInt32(reader["Prop2"]);
         }
         await reader.NextResultAsync();
         if (await reader.ReadAsync()) 
         {
            obj.Prop3 = Convert.ToInt32(reader["Prop3"]);
         }
         // etc...
      }
   }
   return obj;
}

Таким образом, у вас есть только одно соединение с базой данных вместо необходимости создаватьотдельное соединение для собственности на MyObj.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...