Как удалить первый столбец во всех таблицах данных в коллекции таблиц данных С#

Мне нужно проверить данные, возвращенные из запроса Sybase, чтобы проверить первый столбец, который соответствует электронной таблице, в которой будет отображаться данный набор данных. Я могу правильно получить данные в своем наборе данных, но проблема возникает, когда я пытаюсь удалить сгруппированный столбец.

Мои образцы данных выглядят следующим образом:

public static DataTable JustDataTableWithSheetColumn()
{
    var sample = new DataTable();

    sample.Columns.Add("SomethingSheet", typeof(string));
    sample.Columns.Add("Column1", typeof(string));
    sample.Columns.Add("Column2", typeof(string));

    sample.Rows.Add("1", "Somestuff", "this other stuff");
    sample.Rows.Add("1", "Fluffy", "this stuff");
    sample.Rows.Add("2", "ToolShed", "this other stf");
    sample.Rows.Add("2", "FudgeCycles", "this oer stuff");
    sample.Rows.Add("2", "Crap", "thr stuff");
    sample.Rows.Add("2", "stuff and stuff", "thiuff");
    sample.Rows.Add("2", "test crap", "this  stuff");
    sample.Rows.Add("2", "dungheap", "this othuff");
    sample.Rows.Add("3", "people eater", "this other stf");
    sample.Rows.Add("3", "no purple people", "ths oth stff");

    return sample;
}

И следующее правильно группирует и применяет их к таблицам данных:

var thing = DataTableExamples.JustDataTableWithSheetColumn();

if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
    var test = from t in thing.AsEnumerable()
        group t by t.ItemArray[0]
        into g
        select g.ToList().CopyToDataTable();
}

Я пытался без .CopyToDataTable() просто иметь коллекцию DataRows и пытался запросить те, которые используют Skip(1), но я думаю, что мой порядок операций неверен или я нахожусь в этой туманности. Иногда я теряюсь с IEnumerable vs IQueryable и все эти вариации.

Вот так:

datarow.ItemArray.Skip(1).ToArray();

Я также пытался пройти через коллекцию данных и использовать dt.RemoveAt(0), но я не могу сослаться на управляемую таблицу данных (или делаю это неправильно).

foreach (var dt in test)
{ 
    dt.Columns.RemoveAt(0);
}

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

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

Спасибо за вашу помощь.


person Slagmoth    schedule 23.06.2020    source источник
comment
вы хотите тот же datatable без первого столбца?   -  person Mohammed Sajid    schedule 24.06.2020
comment
@Саджид Это было бы идеально. В душе мне пришло в голову, что мне, возможно, придется удалить столбец, прежде чем я заполню таблицу данных, но я еще не пробовал этого. Мне также нужно сохранить ту же базовую структуру, то есть типы данных для каждого столбца, а также имена столбцов.   -  person Slagmoth    schedule 24.06.2020
comment
@Sajid Чтобы было ясно, в этом случае мне нужна одна и та же таблица 3 раза, только не с первым столбцом.   -  person Slagmoth    schedule 24.06.2020
comment
Я думал, что понял тебя, пока не прочитал последний абзац. В заголовке вашего вопроса говорится Как удалить первый столбец во всех таблицах данных в наборе таблиц данных C#, а в последнем абзаце говорится: Я не могу просто удалить все первые столбцы из конечного набора данных - является ли набор таблиц данных подмножеством конечного набора данных? Где эта переменная, которая содержит набор таблиц данных?   -  person Caius Jard    schedule 24.06.2020
comment
@CaiusJard Извинения ... этот набор таблиц данных будет добавлен в набор данных для передачи в вызывающий API, этот набор данных может иметь другие таблицы данных, в которых нет этого первого раздражающего столбца.   -  person Slagmoth    schedule 24.06.2020
comment
Вы можете удалить столбец в источнике, но я думаю, что это будет намного проще удалить позже.   -  person Caius Jard    schedule 24.06.2020
comment
@CaiusJard В идеале я бы хотел, чтобы sprocs возвращал наборы данных, уже сломанные и сгруппированные соответствующим образом, чтобы избежать этого, но я должен исходить из предположения, что это не вариант.   -  person Slagmoth    schedule 24.06.2020
comment
О, я не имел в виду, что далеко назад к источнику - я имел в виду в выборе, после группы LINQ, но вы правы; нет смысла перетаскивать миллион транзакций по сети только для того, чтобы маломощный клиент мог сложить их для получения текущего баланса; многоядерный/gb/disk/everything сервер БД должен сделать это и отправить один номер по сети...   -  person Caius Jard    schedule 24.06.2020


Ответы (2)


dr.ItemArray.Skip(1).ToArray();

Я подозреваю, что это (что бы ни было dr - оно не упоминается в вашем вопросе) было использовано не в том месте, и в итоге вы удалили столбец, по которому хотели сгруппироваться, до того, как группировка была выполнена.

запросите тех, кто использует Skip(1)

Пропуск строки данных не поможет вам пропустить столбец — он просто удаляет всю первую строку данных.


Вы можете просто удалить столбец после подготовки, а не вдаваться в запутанные вопросы:

if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
    var test = from t in thing.AsEnumerable()
        group t by t.ItemArray[0]
        into g
        select g.ToList().CopyToDataTable();

    foreach(var dt in test){
        dt.Columns.RemoveAt(0);
        endDataSet.Tables.Add(dt);
    }
}

Или вы можете манипулировать результирующим набором данных:

    //referencing known table names
    var dtToStrip = new[] { "ATableName", "BTableName" }
    foreach(DataTable dt in endDataSet.Tables)
      if(dtToStrip.Contains(dt.TableName))
        dt.Columns.RemoveAt(0);

    //or removing any column named sheet from any table in the set
    foreach(DataTable dt in endDataSet.Tables)
      if(dt.Columns.Count > 0 && dt.Columns[0].ColumName.Contains("Sheet"))
        dt.Columns.RemoveAt(0);

person Caius Jard    schedule 24.06.2020
comment
Я пытался просмотреть таблицы данных, но по какой-то причине, когда я ссылаюсь на тест, чтобы поместить его в конечный набор данных, у меня все еще есть эти столбцы. - person Slagmoth; 24.06.2020
comment
Я внес правку - объяснение находится в комментарии к вашему ответу. - person Caius Jard; 24.06.2020

Я считаю, что я жертва отложенной казни в этом случае.

Изначально я делал следующее:

if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
    var test = from t in thing.AsEnumerable()
        group t by t.ItemArray[0]
        into g
        select g.ToList().CopyToDataTable();

    foreach (var dt in test)
    { 
        dt.Columns.RemoveAt(0);
    }

    ds.Tables.AddRange(test.ToArray());
}

Я ошибочно предположил, что запрос выполнялся после выполнения первого .ToList(). Но он не был выполнен, пока я не сделал .ToArray() при добавлении его в DataSet в конце. Что, если я правильно понимаю, означает, что все казни в моем foreach были напрасными, потому что они были независимыми казнями.

Если вместо этого я сначала перенесу этот .ToArray() в запрос LINQ, он, похоже, сработает:

if (thing.Columns[0].ColumnName.Contains("Sheet"))
{
    var test = (from t in thing.AsEnumerable()
        group t by t.ItemArray[0]
        into g
        select g.ToList().CopyToDataTable()).ToArray();

    foreach (var dt in test)
    { 
        dt.Columns.RemoveAt(0);
    }

    ds.Tables.AddRange(test);
}

Спасибо за помощь.

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

person Slagmoth    schedule 24.06.2020
comment
Это не совсем отложенное выполнение; запрос LINQ выполняется, когда вы перечисляете его в цикле for, просто он выполнялся снова, когда вы делали ds.Tables.AddRange. Если вы поместите вызов ds.Tables.Add в цикл for, он будет работать, как и следовало ожидать, без ToArray(). test — это запрос; вы можете либо материализовать его с помощью ToArray (что немного напрасно), либо использовать результаты при перечислении. Без ToArray и с for+addrange вы делаете запрос, запускаете его, перечисляете его в for, отбрасываете результат, а затем AddRange выполняет собственное перечисление/выполнение. - person Caius Jard; 24.06.2020
comment
@CaiusJard Можете ли вы уточнить, почему это немного напрасный шаг, пожалуйста? Я попытался убедиться, что я использую отложенное выполнение там, где это необходимо, но если мне требуется результат коллекции только тогда, когда у меня сложилось впечатление, что было бы дешевле получить то, что мне нужно, а затем манипулировать коллекцией объектов в этот момент. Я понимаю, что в обоих случаях это происходит, но я думаю, я не понимаю, что происходит под капотом с различиями, на которые вы намекаете. - person Slagmoth; 24.06.2020
comment
Это не отложенное выполнение как таковое; LINQ — это отложенное выполнение, и независимо от того, делаете ли вы первое, что вы делаете после того, как сформулируете запрос, ToArray() или foreach, вы выполняете его и перечисляете, так что ничто не отложено (больше, чем могло бы быть). иначе было). Я утверждаю, что LINQ подготавливает массив из перечислимого, а затем перечисляет массив, это напрасный шаг, просто потому, что можно перечислить перечисляемое, поэтому процесс создания массива должен быть напрасным шагом. См. также stackoverflow.com/questions/1105990/ - person Caius Jard; 24.06.2020
comment
(Я должен был уточнить, что это напрасный шаг в этом случае - будет бесчисленное множество других случаев, когда вызов ToXxx по запросу linq для запуска запроса и материализации результатов в коллекцию и сохранение коллекции - это то, что вы хотите сделать.. Вы также можете сказать, что foreach и помещение таблиц в набор данных — это одно и то же, и вы будете правы, мы делаем это в этом случае, потому что нам нужен набор данных, а ToDataSet ( ), который превращает IEnumerable<DataTable> в DataSet (коллекцию данных как таковую), как есть ToArray, который превращает IEnumerable<sring> в string[]) - person Caius Jard; 24.06.2020