Существуют ли альтернативы для извлечения классов из соединений LINQ to SQL и отображений [Table]? - PullRequest
1 голос
/ 10 марта 2011

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

Итак, .Net играет хорошо, когда у вас есть простой, прямой LINQ:

Invoice tbl_invoice = from invoice in DbContext.Invoice 
                      where invoice.RecordID == 1 
                      select invoice;

Предполагается, что класс Invoice существует следующим образом:

[Table]
public class Invoice
{
    [Column]
    public int RecordID {get; set;}

    [Column]
    public DateTime RecordDate {get; set;}
}

УчитываяПри выполнении примера LINQ вышеупомянутый класс будет инстанцирован с соответствующими значениями в атрибутах атрибута Column.

Давайте немного продвинем запрос:

var purchases = (from invoice in DbContext.Invoice 
                 join order in DbContext.Order on invoice.RecordID equals order.InvoiceID 
                 select new ProductPurchase 
                 { 
                     invoice.RecordID, 
                     invoice.RecordDate, 
                     order.PartID, 
                     order.Quantity 
                 })
                .ToList();    // this is used to create a BindingList<ProductPurchase>

Должно быть два класса, которые напоминают следующее:

[Table]
public class Order
{
    [Column]
    public int InvoiceID {get; set;}

    [Column]
    public string OrderID {get; set;}

    [Column]
    public string Quantity {get; set;}
}

[Table]
public class ProductPurchase : Invoice
{
    [Column]
    public int InvoiceID {get; set;}

    [Column]
    public string PartID {get; set;}

    [Column]
    public string Quantity {get; set;}
}

Цель во втором примере - создатьBindingList<T>, чтобы данные могли использоваться в качестве источника данных.Итак, со вторым примером LINQ мы могли бы сделать следующее:

BindingList<ProductPurchase> purchases = new BindingList<ProductPurchase>(purchases);

Мы не можем сделать это так легко, как кажется.Мы должны наследовать конкретные классы, чтобы это работало.На мой взгляд, это очень неэлегантно.Я подумал, было бы неплохо, если бы я мог создать интерфейс. Что-то вроде:

[Table]
public interface IInvoice
{
    [Column]
    public int RecordID {get; set;}

    [Column]
    public DateTime RecordDate {get; set;}
}

Теперь предположим, что есть аналогичный интерфейс IOrder, я мог бы создать конкретный класс ProductPurchaseследующим образом:

[Table]
public class ProductPurchase : IInvoice, IOrder
{  }

... IF [TableAttribute()] были разрешены на интерфейсах.

Допустим, я хочу включить join в PartID в tblParts, который будет извлекать PartsDescription и PartsCost;только один базовый (конкретный или абстрактный) класс может быть унаследован.Похоже, вам нужно создать кучу ненужных дериваций, чтобы иметь возможность разместить соединения.Есть ли альтернатива?Я устал от использования DataTable / DataView в качестве источника данных для DataGridView.Было бы намного проще использовать классы, которые я создал, в качестве отображений.

Один пример задачи, которую я пытаюсь выполнить:

  1. Вывод списка записей в DataGridView с отображением определенных объединенных данных.
  2. Пользователь дважды щелкает по выбранному представлению строки таблицы данных.
  3. Новая WinForm теперь отображает запрошенную информацию из нескольких объединенных таблиц

На шаге 2, когда пользователь выбирает Счет, я преобразую DataGridRowView в DataRow.Не так уж и плохо.Но когда я заканчиваю запрос, у меня появляется анонимный тип данных, который можно использовать для создания экземпляра новой DataTable и заполнения значений DataRow.

Привязка DataRow к новой WinForm не так проста, как привязка класса.Таким образом, мой вопрос и любопытство об альтернативах.Любые идеи будут полезны.

РЕДАКТИРОВАТЬ: Несколько ссылок, которые объясняют немного больше:

РЕДАКТИРОВАТЬ 2:
Допустим, у меня есть запрос из 3 таблиц:

tblInvoices :
InvoiceID |InvoiceDate |Баланс |Платный |PaidDate

tblPurchaseItem :
PartNumber |InvoiceID |PartCost |PartDescription

tblInventory : PartNumber |OnHands |Заказать |Restock

Предположим, что есть 3 класса, украшенные атрибутом отображения [Table] со всеми соответствующими атрибутами отображения [Column] {get;задавать;}.

У меня может быть метод, похожий на следующий:

public static BindingList<InvoiceDetails> GetInvoiceDetails (int InvoiceID)
{
    // LINQ is probably incorrect - feel free to post corrections :)
    IList<InvoiceDetails> invDetails = (from purchItems in DbContext.PurchaseItemsMap 
                                        join invoices in DbContext.Invoices 
                                            on purchItems.InvoiceID equals invoices.InvoiceID
                                        join invItems in DbContext.InventoryItemsMap
                                            on purchItems.PartNumber equals invItems.PartNumber
                                        where purchItems.InvoiceID == InvoiceID
                                        where invItems.Restock == true
                                        select new InvoiceDetails
                                        {
                                            invoices.InvoiceID,
                                            purchItems.PartDescription,
                                            purchItems.PartCost,
                                            invItems.OnHands
                                        })
                                        .ToList();

    return new BindingList(invDetails);
}

Чтобы это работало, мне понадобится следующее:

[Table]
public class InvoiceDetails : PurchaseItems
{  // invoices column getters & setters  }

[Table]
public class PurchaseItems : InventoryItems
{  // purchasItems column getters & setters  }

[Table]
public class InventoryItems
{  // inventoryItems column getters & setters  }

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

public class InvoiceDetails : IInventoryItems, IPurchaseItems, IInvoices
{    }

1 Ответ

1 голос
/ 21 марта 2011

Часто вы можете использовать анонимный класс и избавить от головной боли.

Однако, если вы хотите использовать его как явный тип, тогда вы действительно можете использовать интерфейс. Однако вам не нужно указывать интерфейс как [Table]. Ваш пример:

[Table]
public interface IInvoice
{
    [Column]
    public int RecordID {get; set;}

    [Column]
    public DateTime RecordDate {get; set;}
}

[Table]
public class ProductPurchase : IInvoice, IOrder
{  }

Может отлично работать как:

public interface IInvoice
{
    public int RecordID {get; set;}

    public DateTime RecordDate {get; set;}
}

[Table]
public class ProductPurchase : IInvoice, IOrder
{  }

В конце концов, [Table] и [Column] используются только для самого кода Linq2SQL при создании отображений между базой данных и .NET и кодом, который их получает и т. Д. Код, воздействующий на объекты любым другим способом, не требует не заботятся об этих атрибутах. Следовательно, код может работать с IInvoice независимо от того, является ли класс реализации [Table] или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...