簡體   English   中英

如何編寫返回實例集合的類方法

[英]How to write class methods that return collections of instances

我正在努力定義一個填充並返回實例集合的類方法。 我不知道如何解決的問題是我有私人屬性來填充。

讓我們使用Book類的示例。 我不希望代碼直接設置(說)書的可用性。 我希望代碼必須在Book實例上使用CheckOut方法。 所以我們有類似的東西:

public class Book
{
  private int ID;
  private bool pAvailableForCheckout;

  public string Title { get; set; }
  public bool AvailableForCheckout { get { return pAvailableForCheckout } }

  // instance methods

  public Book(int BookID)
  {
     // Load book from DB by ID
  }
  public CheckOut()
  {
     // perform everything involved with checking a book out
  }
  // .. other methods like saving a book, checking out books etc.

  // class method

  public static List<Book> FindAll()
  {
     // load Dataset of books
     // foreach record in DB, use the Book(int BookID) constructor and add to List
     // return list of books
  }
}

所以,我可以在我的代碼中使用它:

foreach(Book curBook in Book.FindAll())
  { /* do something with book */ }

上述實現的問題是我必須使用N + 1命中數據庫來加載所有書籍,而不是只加載1個查詢。 我該如何解決這個問題?

我確定這是編程101,但我需要問。

您可以創建一個受保護的構造函數,直接填充私有屬性。

foreach應該迭代已經實例化的對象列表,它們不需要連接到DB。

您需要創建一個接受book對象屬性的構造函數,以便您可以從現有數據集中實例化一本書,而不是對數據庫進行新的命中。

所以:

構造函數:

public book (String title, String avail) {Title=title...}

並在方法中

public static void FindAll()
{
List<Books> books = new List<books>();
using (Sqlconnection conn = new sqlconnection(connstring))
using (sqlcommand cmd = new SqlCommand("select title, available from book ", conn)
{
  SqlDatareader dr = cmd.executereader()
  while (dr.read())
  {
    books.add(new Book(dr["title"], dr["avail"])
  }

}

foreach(Book curBook in Book.FindAll())
  { /* do something with book */ }

}

例如,它的意識形態純度有點極端:

首先,一個類的接口,可以從數據庫中檢索類型為T的對象,並給出它們的ID:

interface IAdapter<T>
{
   T Retrieve(int id);
}

現在, Book類不再公開一個公共構造函數,而是一個靜態方法,它使用IAdapter<Book>從數據庫中檢索書籍:

public class Book
{
    public static IAdapter<Book> Adapter { get; set; }

    public static Book Create(int id)
    {
       return Adapter.Retrieve(id);
    }

    // constructor is internal so that the Adapter can create Book objects
    internal Book() { }

    public int ID { get; internal set; }
    public string Title { get; internal set; }
    public bool AvailableForCheckout { get; internal set; }

}

您必須自己編寫實現IAdapter<Book>的類,並將Book.Adapter分配給它的實例,以便Book.Create()能夠從數據庫中提取內容。

我說“意識形態的純潔性”,因為這種設計強制執行相當嚴格的關注點分離: Book類中沒有任何內容知道如何與數據庫通信 - 甚至有數據庫。

例如,這是IAdapter<Book>的一種可能實現:

public class DataTableBookAdapter : IAdapter<Book>
{
   public DataTable Table { get; set; }
   private List<Book> Books = new List<Book>();

   Book Retrieve(int id)
   {
      Book b = Books.Where(x => x.ID = id).FirstOrDefault();
      if (b != null)
      {
         return b;
      }

      BookRow r = Table.Find(id);
      b = new Book();

      b.ID = r.Field<int>("ID");
      b.Title = r.Field<string>("Title");
      b.AvailableForCheckout = r.Field<bool>("AvailableForCheckout");

      return b;
   }
}

其他一些類負責創建和填充此類使用的DataTable 您可以編寫一個使用SqlConnection直接與數據庫通信的不同實現。

你甚至可以這樣寫:

public IAdapter<Book> TestBookAdapter : IAdapter<Book>
{
   private List<Book> Books = new List<Book>();

   public TestBookAdapter()
   {
      Books.Add(new Book { ID=1, Title="Test data", AvailableForCheckout=false };
      Books.Add(new Book { ID=2, Title="Test data", AvailableForCheckout=true };
   }

   Book Retrieve(int id)
   {
      return Books.Where(x => x.ID == id);
   }
}

這個實現根本不使用數據庫 - 你在為Book類編寫單元測試時會使用它。

請注意,這兩個類都維護一個私有的List<Book>屬性。 這保證了每次使用給定的ID調用Book.Create()時,都會返回相同的Book實例。 有制作這個的功能進行參數Book類,而不是-你會是一個靜態的私人List<Book>財產Book ,寫的邏輯,使Create方法維護它。

您使用相同的方法將數據推送回數據庫 - 將UpdateDeleteInsert方法添加到IAdapter<T>並在適配器類中實現它們,並讓Book在適當的時候調用這些方法。

為什么不使用SQL where語句在數據庫端檢查本書的可用性?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM