Entity Framework — сложный запрос — и экспорт в CSV

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

Мой SQL-запрос:

select o.product, o.invoicenr, o.amount as quantity, o.price, o.shipping, o.vatrate, o.datecreated, os.title as [orderstatus],ps.title as [paymentstatus], pm.title as [paymentmethod], o.datepaid, o.dateinvoice,
c.*, a.*,
oos.trackingcode, oos.courier, oos.datecreated as [orderstatusdate],
 p.amout, p.transactionIdentifier, p.comment, p.datecreated as [paymentcreated]
 from [order] o
    inner join Address a
        on o.shipingaddressId = a.id
    inner join Customer c
        on o.customerId = c.id
    inner join OrderOrderStatus oos
        inner join OrderStatus os
         on oos.orderstatusId = os.id
         on o.id = oos.orderID      
    inner join Payment p 
        inner join PaymentStatus ps
         on p.paymentstatusId = ps.id
        inner join PaymentMethod pm
         on p.paymentmethodId = pm.id
        on o.id = p.orderId
order by o.datecreated, o.id

В совокупности должно быть возвращено 44 столбца.

Как я могу воспроизвести этот запрос с помощью LINQ? Каков наилучший способ приступить к этой задаче в целом?

Просто для понимания: есть основная таблица «Заказ», которая связана один ко многим с таблицами «Адрес», «Клиент», «Статус заказа» и «Оплата». Таблица Payment имеет отношение "один ко многим" с PaymentStatus и PaymentMethod. Таблица OrderOrderStatus имеет связь "один ко многим" с OrderStatus.

Спасибо!


person lekso    schedule 03.11.2013    source источник
comment
Пожалуйста, покажите модель класса со свойствами навигации. Большинство объединений можно выполнить с помощью свойств навигации. Также поможет первый набросок того, что вы пробовали.   -  person Gert Arnold    schedule 03.11.2013


Ответы (1)


Вот как я решил проблему (не только запрос, но и экспорт CSV):

Этот метод возвращает действительный файл CSV:

public string GetCSV(DateTime startDate, DateTime endDate, string separator = ",")
{
    var data = this.GetData(startDate, endDate);
    var csvData = this.ToCsv("\"" + separator + "\"", data);
    var result = string.Join(Environment.NewLine, csvData);

    return result;
}

Приведенный ниже метод создает объект IEnumerable<string> из данных. Взято из этой замечательной ветки o">Рекомендации по сериализации объектов в пользовательский формат строки для использования в выходном файле

public IEnumerable<string> ToCsv<T>(string separator, IEnumerable<T> objectlist)
{
    PropertyInfo[] properties = typeof(T).GetProperties();
    yield return "\"" + String.Join(separator, properties.Select(f => f.Name).ToArray()) + "\"";
    foreach (var o in objectlist)
    {
        yield return "\"" + HttpUtility.HtmlDecode(string.Join(separator, properties.Select(f => (f.GetValue(o) ?? "").ToString()).ToArray())) + "\"";
    }
}

Обратите внимание, что с помощью вышеуказанного метода действительный CSV будет создан только в том случае, если ваш объект хранит значения в свойствах, а не в полях.

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

private IEnumerable<Models.DataExport> GetData(DateTime startDate, DateTime endDate)
{
    using (var db = new DAL.smigEntities())
    {
        CultureInfo deDE = CultureInfo.CreateSpecificCulture("de-DE");

        return db.Order
            .Where(x => x.datecreated >= startDate && x.datecreated <= endDate).AsEnumerable()
            .Join(db.Payment, Order => Order.id, Payment => Payment.orderId, (Order, Payment) => new Models.DataExport
            {
                Id = Order.id,
                Product = Order.product,
                Invoicenr = Order.invoicenr,
                Quantity = string.Format("{0:0}", Order.amount),
                Price = string.Format(deDE, "{0:0.00}", Order.price),
                Shipping = string.Format(deDE, "{0:0.00}", Order.shipping),
                Vatrate = string.Format(deDE, "{0:0.00}", Order.vatrate),
                Datecreated = Order.datecreated,
                Datepaid = Order.datepaid,
                Dateinvoice = Order.dateinvoice,
                Paymentrecorddate = Payment.datecreated,
                Paymentstatus = Payment.PaymentStatus.title,
                Paymentmethod = Payment.PaymentMethod.title,
                Paidamount = string.Format(deDE, "{0:0.00}", Payment.amout),
                Transactionidentifier = Payment.transactionIdentifier,
                Comment = Payment.comment,
                Title = Order.Address.title,
                Name = Order.Address.name,
                Lastname = Order.Address.lastname,
                Recepient2 = Order.Address.recepient2,
                Company = Order.Address.company,
                Address1 = Order.Address.address1,
                Address2 = Order.Address.address2,
                Address3 = Order.Address.address3,
                Town = Order.Address.town,
                Postcode = Order.Address.postcode,
                County = Order.Address.county,
                Country = Order.Address.country,
                Email = Order.Customer.email,
                Balancerelevant = Payment.PaymentStatus.balancerelevant.Value
            })
            .OrderByDescending(x => x.Datecreated).ThenByDescending(x => x.Id).ThenByDescending(x => x.Paymentrecorddate)
            .ToList();
    }
}

Надеюсь, это поможет кому-то

person lekso    schedule 03.11.2013