Заполнение DataSet или DataTable из набора результатов запроса LINQ

Как представить запрос LINQ как веб-службу ASMX?
Обычно с бизнес-уровня я могу вернуть типизированный DataSet или DataTable сериализованный для передачи через ASMX.

Как я могу сделать то же самое для запроса LINQ?
Есть ли способ заполнить типизированный запрос DataSet или DataTable запрос LINQ?

public static MyDataTable CallMySproc()
{
    string conn = "...";

    MyDatabaseDataContext db = new MyDatabaseDataContext(conn);
    MyDataTable dt = new MyDataTable();

    // execute a sproc via LINQ
    var query = from dr
                in db.MySproc().AsEnumerable
                select dr;

    // copy LINQ query resultset into a DataTable -this does not work !    
    dt = query.CopyToDataTable();
   
    return dt;
}

Как я могу поместить набор результатов запроса LINQ в DataSet или в DataTable ?
В качестве альтернативы, можно ли сериализовать запрос LINQ, чтобы я мог предоставить его как веб-службу ASMX?

Ответов (7)

Решение

Как уже упоминалось в вопросе, IEnumerable есть CopyToDataTable метод:

IEnumerable<DataRow> query =
    from order in orders.AsEnumerable()
    where order.Field<DateTime>("OrderDate") > new DateTime(2001, 8, 1)
    select order;

// Create a table from the query.
DataTable boundTable = query.CopyToDataTable<DataRow>();

Почему это не сработает для вас?

Создайте объект класса и верните list(T) запрос.

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

Чтобы выполнить этот запрос к DataContext классу, вам необходимо сделать следующее:

MyDataContext db = new MyDataContext();
IEnumerable<DataRow> query = 
    (from order in db.Orders.AsEnumerable()
        select new
        {
            order.Property,
            order.Property2
        })
    as IEnumerable<DataRow>;
return query.CopyToDataTable<DataRow>();

Без этого as IEnumerable<DataRow>; вы увидите следующую ошибку компиляции:

Невозможно неявно преобразовать тип System.Collections.Generic.IEnumerable в System.Collections.Generic.IEnumerable. Существует явное преобразование (вам не хватает приведения?)

Если вы используете IEnumerable в качестве возвращаемого типа, он вернет вашу переменную запроса напрямую.

MyDataContext db = new MyDataContext();
IEnumerable<DataRow> query = 
    (from order in db.Orders.AsEnumerable()
        select new
        {
            order.Property,
            order.Property2
        })
    as IEnumerable<DataRow>;
return query.CopyToDataTable<DataRow>();

Для полноты картины эти решения не работают для EF Core (по крайней мере, для EF Core 2.2). Приведение к IEnumerable<DataRow>, как предлагается в других ответах здесь, не выполняется. Реализация этого класса и методов расширения сработала для меня https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/implement-copytodatatable-where-type-not-a-datarow .

Я не знаю, почему он не встроен в EF Core.

Если вы используете тип возвращаемого значения IEnumerable, вы можете напрямую вернуть свою переменную запроса .