[英]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
方法維護它。
您使用相同的方法將數據推送回數據庫 - 將Update
, Delete
和Insert
方法添加到IAdapter<T>
並在適配器類中實現它們,並讓Book
在適當的時候調用這些方法。
為什么不使用SQL where語句在數據庫端檢查本書的可用性?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.