Приведение Linq к IEnumerable

#c# #linq

#c# #linq

Вопрос:

Я создаю приложение WinForm, при нажатии этой кнопки я собираю таблицы данных из двух баз данных Mysql и Sqlite database. Я получаю ошибку приведения при приведении запроса Linq к IEnumerable для преобразования значений запроса в DataTable для отображения в представлении DataGrid.

 private void button1_Click(object sender, EventArgs e)
{

    var obj = new table1TableAdapter();  //Mysql Table Adapter
    var obj2 = new Table1TableAdapter(); // Sqlite Table Adapter
    var ds = new DataSet();
    ds.Tables.Add(obj.GetData());
    ds.Tables.Add(obj2.GetData());
    var tab1 = ds.Tables[0];
    var tab2 = ds.Tables[1];
    var query = from o in tab1.AsEnumerable()
                join od in tab2.AsEnumerable()
                on o.Field<string>("Name") equals od.Field<string>("Name")
                select new
                {
                    Name = o.Field<string>("Name"),
                    Rollno = od.Field<Int64>("rollno"),
                    Book = o.Field<string>("Book")
                };

    var q2 = (IEnumerable<DataRow>)query; //Unable to cast object of type <JoinIterator>

    DataTable orderTable = q2.CopyToDataTable();
    dataGridView1.DataSource = orderTable;
}
  

Комментарии:

1. Это не поток данных, и вы не можете волшебным образом превратить его в DataRow

Ответ №1:

Глядя на ваш код, я бы сказал, зачем вообще приводить его к IEnumerable<DataRow> ? Просто привяжите запрос к вашему GridView.

 dataGridView1.DataSource = query.ToList();
  

Ответ №2:

Это потому, что возвращаемый вами объект запроса не имеет никакого отношения к DataRow . query это будет IEnumerable<SomeAnonymousType> . Как ожидается преобразование в DataRow ?

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

 select new DataRow(/* Whatever Params */) { /* More Params */ };
  

Тогда это изначально IEnumerable<DataRow> и не нуждается в приведении.

Ответ №3:

Поскольку ваш запрос создает IEnumerable, вы не смогли бы привести его к потоку данных. Я бы также не советовал использовать select new DataRow(/* Любые параметры /) { / Больше параметров * / }; поскольку это не было бы истинным объектом DataRow и было бы плохой практикой.

Я бы справился с этим таким образом. Даже если это небольшой проект, в вашем обработчике Button_Click не должно быть такого большого количества кода.

Сначала создайте объект-контейнер, назовите его DTO или ViewModel. Я предлагаю позже.

 public class BookViewModel
{
    public string Name { get; set; }

    public Int64 Rollno { get; set; }

    public string Book { get; set; }
}
  

Затем создайте новый класс, который будет выполнять ваши SQL-запросы. Это отделит вашу логику доступа к данным от вашей логики формы.

 public class BookService
{
    public IList<BookViewModel> GetBookViewModel()
    {
        var obj = new table1TableAdapter();  //Mysql Table Adapter
        var obj2 = new Table1TableAdapter(); // Sqlite Table Adapter
        var ds = new DataSet();
        ds.Tables.Add(obj.GetData());
        ds.Tables.Add(obj2.GetData());
        var tab1 = ds.Tables[0];
        var tab2 = ds.Tables[1];
        var query = from o in tab1.AsEnumerable()
                    join od in tab2.AsEnumerable()
                    on o.Field<string>("Name") equals od.Field<string>("Name")
                    select new BookViewModel
                    {
                        Name = o.Field<string>("Name"),
                        Rollno = od.Field<Int64>("rollno"),
                        Book = o.Field<string>("Book")
                    };

        return query.ToList();
    }

}
  

Наконец, привяжите список к вашему дисплею.

  private void button1_Click(object sender, EventArgs e)
    {
        BookService bookService = new BookService();
        dataGridView1.DataSource = bookService.GetBookViewModel();
    }
  

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

Пример:

  private void button1_Click(object sender, EventArgs e)
        {
            BookService bookService = new BookService();
            IList<BookViewModel> books = bookService.GetBookViewModel();
            if (books.Count == 0)
            {
                        Label1.Text = "Sorry no books were found";
            }
            dataGridView1.DataSource = books;
        }
  

Ответ №4:

Во-первых, вы не сможете выполнить приведение к IEnumerable, потому что сам ваш запрос не генерирует потоки данных

 select new
{
    Name = o.Field<string>("Name"),
    Rollno = od.Field<Int64>("rollno"),
    Book = o.Field<string>("Book")
};
  

создает анонимный тип.

Сначала вам пришлось бы каким-то образом изменить это на DataRow, а затем преобразовать его в IEnumerable.

Ответ №5:

Я использую следующую инструкцию, и это работает для меня

 UC070_WizardStepFilesDataSet.AllDossierDetailResultsRow[] searchrows =
                        (from a in _wizardStepPreviewDataSet.AllDossierDetailResults
                        where a.WingsSetNbr == row.WingsSetNbr amp;amp; !a.BookCode.StartsWith("V")
                        select a).ToArray<UC070_WizardStepFilesDataSet.AllDossierDetailResultsRow>();