Как применить оператор SQL к одному или нескольким объектам DataTable? - PullRequest
0 голосов
/ 25 марта 2019

Вопрос

Пожалуйста, помогите мне написать подпрограмму на C # или vb.net, которая будет принимать

  • a DataTable
  • запрос SQL как string

и создайте

  • a DataTable с результатом запроса, примененного к входной таблице DataTable

Насколько мне известно, инструментом для запуска SQL в .net является linq, но это не приводит меня к решению.

В терминах VB.net: как реализовать такую ​​функцию

Public Function SelectFromDataTable(Sql As String, T1 As DataTable) As DataTable
        // Apply Sql to T1
    End Function

(или даже лучше, вот так)

Public Function SelectFromDataTable(Sql As String, T1 As DataTable, Optional T2 As DataTable) As DataTable
        // Apply Sql to T1 and T2
    End Function

Что я пробовал до сих пор

По какой-то причине я подумал, что решение может быть linq, но это не является обязательным требованием.

Пробная версия 1

если я посмотрю на комбинацию linq и DataTable, я получу тот типичный синтаксис, в котором вы напишете sql-подобный код, встроенный в ваш код .net, как on. Запросы в LINQ to DataSet

Я хочу, чтобы запрос был определен вне моей подпрограммы, поэтому Вы также можете создавать такие запросы из строки SQL ?

Пробная версия 2

В поисках комбинации linq и SQL я получаю примеры, использующие SqlDataAdapter, но им нужен SqlConnection, который, очевидно, должен указывать на базу данных, как в Как получить SQL-оператор как DataTable

Однако для меня DataTable должен быть не только пункт назначения, но и источник, поэтому Вы также можете создать SqlConnection для DataTables ?

Контекст

Если вам интересно, откуда мой вопрос:

BluePrism - это графический роботизированный инструмент автоматизации процессов (RPA). У него есть один контейнерный объект, называемый collection, который находится под капотом .net DataTable и дает очень небольшую поддержку для манипулирования ими.

К счастью, в .net можно создать так называемые «бизнес-объекты» и реализовать «действие», которое получает и возвращает переменные. (Это предназначено для манипулирования другими приложениями, но также может использоваться для манипулирования данными.)

У нас уже есть такой объект, который мы назвали Collection Manipulation. Одно из действий, Filter Collection, реализовано как

Dim NewRow As DataRow

Collection_Out = Collection_In.Clone

For Each parentRow As DataRow In Collection_In.Select(Select_Condition)
    NewRow = Collection_Out.NewRow
    For Each c As DataColumn In NewRow.Table.Columns
        NewRow(c.ColumnName) = parentRow(c.ColumnName)
    Next
    Collection_Out.Rows.Add(NewRow)
Next

NewRow = Nothing
Collection_In = Nothing

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

select category, sum(unit_price * units) as total_price 
from invoice 
group by category;

select article, order.units - delivery.units as units_missing 
from order, delivery 
where order.article = delivery.article;

1 Ответ

1 голос
/ 27 марта 2019

Если я правильно понял ваш вопрос, вам нужен синтаксис SQL, например, многоцелевой выбор для таблиц данных.

На основании информации, найденной здесь: https://www.hanselman.com/blog/TheWeeklySourceCode48DynamicQueryableMakesCustomLINQExpressionsEasier.aspx, Я написал следующий пример ниже. Вы можете расширить его, как считаете нужным.

TL; DR Добавьте пакет System.Linq.Dynamic NuGet, чтобы вы могли использовать строки для предложений where среди других.

КСТАТИ: Написание синтаксического анализатора строки запроса, для анализа, например, «выберите категорию, сумма (единица_ценки * единиц) как total_price из группы счетов по категории;» вполне возможно, но ИМХО вы потратите много времени, чтобы получить немного.

using System.Data;
using System.Linq;
using System.Linq.Dynamic;

namespace Foo {
    public class Bar {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="from"></param>
        /// <param name="where"></param>
        /// <param name="skipRows"></param>
        /// <param name="takeRows"></param>
        /// <param name="orderBy">Needed for range selections (skipRows, takeRows) </param>
        /// <returns></returns>
        public DataTable GeneralPurposeSelect(DataTable from, string where = null, int? skipRows = null, int? takeRows = null, string orderBy = "Id") {
            var fromQryAble = from.AsEnumerable().AsQueryable();

            IQueryable<DataRow> toQryAble = null;
            if (!string.IsNullOrEmpty(where)) {
                toQryAble = fromQryAble.Where(where);
            }
            if (takeRows != null) {
                if (skipRows == null) {
                    skipRows = 0;
                }
            }
            if (skipRows != 0) {
                if (takeRows == null) {
                    takeRows = int.MaxValue;
                }
            }
            if (takeRows != null) {
                if (skipRows == null) {
                    skipRows = 0;
                }
                toQryAble = toQryAble == null ?
                    fromQryAble.OrderBy(orderBy).Skip(skipRows.Value).Take(takeRows.Value) :
                    toQryAble.OrderBy(orderBy).Skip(skipRows.Value).Take(takeRows.Value);
            }

            return toQryAble == null ? from : toQryAble.CopyToDataTable();
        }
    }
}
...