Вам следует больше поработать над разделением проблем : отделите метод внутреннего хранения ваших данных (DataTables) от обработки данных (объедините данные в ваших таблицах данных с помощью операторов LINQ).
В вашем случае рассмотрите возможность создания функций расширения для DataTable
: функций, преобразующих DataTable
в IEnumerable<Customer>
и IEnumerable<Appointment>
, и функций, преобразующих IEnumerable<Customer>
/ IEnumerable back into a
DataTable`.
Если вы сделаете это, вам будет легче распознавать шаблоны и повторно использовать код. Кроме того, если вы измените свое хранилище данных, например, с DataTable
на CSV-файл, или базу данных, или что-то еще, все, что вам нужно сделать, это написать функцию, которая сделает его IEnumerable
/ IQueryable
, и ваши LINQ-запросы все еще будут работать.
См. Демистифицированные методы расширения
static class DataTableExtensions
{
public static IEnumerable<Customer> ToCustomers(this DataTable table)
{
... // TODO: implement
}
public static DataTable ToDataTable(this IEnumerable<Customer> customers)
{
... // TODO implement
}
// similar functions for Appointments and AppointmentDetails:
public static IEnumerable<Appointment> ToAppointments(this DataTable table) {...}
public static DataTable ToDataTable(this IEnumerable<Appointment> appointments) {...}
public static IEnumerable<AppointmentDetails> ToAppointmentDetails(this DataTable table) {...}
public static DataTable ToDataTable(this IEnumerable<AppointmentDetail> appointmentDetails) {...}
Вы знаете DataTables лучше, чем я, поэтому я оставлю вам код. Для получения справки см. Преобразовать DataTable в IEnumerable и Преобразовать IEnumerable в DataTable
Нам нужно написать функцию для вашего запроса LINQ. Вы можете сохранить его в виде набора операторов LINQ, однако он будет выглядеть аккуратнее, лучше читаемым, лучше тестируемым, более пригодным для повторного использования, если вы напишите для этого функцию (в конце концов: вы уже знаете, как писать функции расширения:
public static IEnumerable<AppointmentDetail> ToAppointmentDetails(
this IEnumerable<Customer> customers,
IEnumerable<Appointment> appointments)
{
return customers.GroupJoin(appointments, // GroupJoin customer and appointments
customer => customer.CustomerId, // from every customer take the customerId,
appointment => appointment.CustomerId, // from every appointment take the CustomerId,
// from every Customer with all his matching Appointments make one new AppointmentDetail
(customer, appointments => new AppointmentDetail
{
CustomerId = customer.CustomerId,
TotalAppointments = appointments.Count(),
MissedAppointments = appointments
.Where(appointment => appointment.IsMissed)
.ToList(),
...
});
}
Теперь соберите все вместе:
Использование:
DataTable customerTable = ...
DataTable appointmentTable = ...
IEnumerable<Customer> customers = customerTable.ToCustomers();
IEnumerable<Appointment> appointments = appoitnmentTable.ToAppointments();
IEnumerable<AppointmentDetail> appointmentDetails = customers.ToAppointmentDetails(appointments);
DataTable appointmentDetailTables = appointmentDetails.ToDataTable(appointmentDetails);
Разве это не выглядит лучше?
Обратите внимание, что перечисление будет выполнять только последнее утверждение. Все более ранние операторы только создают IEnumerable, перечисление не выполняется. Это очень похоже на объединение операторов LINQ. Фактически, если вы действительно хотите и можете убедить своего руководителя проекта в том, что код будет лучше читаемым, тестируемым, обслуживаемым (в чем я сомневаюсь), вы можете переписать его одним оператором, аналогично объединению операторов LINQ. Не думайте, что это улучшит скорость обработки:
DataTable appointmentDetailTable = customerTable.ToCustomers()
.ToAppointmentDetails(appointmentTable.ToAppointments())
.ToDataTable();
Поскольку вы разделили свои проблемы, этот код гораздо более пригоден для повторного использования. Небольшие изменения не сильно повлияют на ваш код. Если вы решите, что ваши Клиенты и Назначения должны выбираться из базы данных, а не из DataTable, все, что вам нужно сделать, это переписать ваши ToCustomers
и ToAppointments
, все остальные функции останется без изменений.