2009-02-17 2 views
4

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

Давайте рассмотрим пример класса книги. Я не хочу, чтобы код напрямую устанавливал (скажем) доступность книги. Я хочу, чтобы код должен был использовать метод 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 обращения к базе данных для загрузки всех книг вместо одного запроса. Как мне обойти это?

Я уверен, что это программирование 101, но мне нужно было спросить.

ответ

2

Вы можете создать защищенный конструктор, который напрямую заполняет частные свойства.

+0

Приятный Я даже не думал об этом, но это кажется довольно очевидным, когда вы это говорите. –

0

Почему вы не проверяете доступность книги на стороне базы данных с помощью инструкции SQL where?

2

Предпросмотр должен быть итерированием по списку уже созданных объектов, им не нужно подключаться к БД.

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

так:

Конструктор:

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 */ } 

} 
+0

Я согласен с этим ответом. Классы доменов не должны знать о базе данных. – Bertvan

1

Для примера, несколько экстремальных в своей идеологической чистоты:

Во-первых, интерфейс для классов которые могут извлекать объекты типа 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>. Это гарантирует, что каждый раз, когда вы вызываете Book.Create() с данным ID, вы получаете тот же экземпляр Book. Будет аргумент, который нужно сделать для того, чтобы сделать эту функцию классом Book вместо этого - вы сделаете статическое приватное свойство List<Book> в Book и напишите логику, чтобы поддерживать метод Create.

Вы используете один и тот же подход для выталкивания данных обратно в базу данных - добавить Update, Delete и Insert методы IAdapter<T> и реализовать их в классах адаптеров и имеет Book вызов этих методов в соответствующее время.

+0

+1 для того, чтобы мой мозг взорвался. Очень приятно, мне придется поиграть с IAdapters, по-видимому. Всегда хорошо видеть еще одну реализацию, поэтому я думаю, что я собираюсь извлечь много из этого примера. –

 Смежные вопросы

  • Нет связанных вопросов^_^