인스턴스 모음을 반환하는 클래스 메소드를 작성하는 방법
-
05-09-2019 - |
문제
인스턴스 모음을 채우고 반환하는 클래스 방법을 정의하기 위해 고군분투하고 있습니다. 내가 돌아 다니는 방법을 모르는 문제는 채워야 할 개인 속성이 있다는 것입니다.
책 수업의 예를 사용합시다. 코드가 책의 가용성을 직접 설정 (예 :)하고 싶지 않습니다. 코드가 책 인스턴스에서 결제 방법을 사용해야합니다. 그래서 우리는 다음과 같은 것을 가지고 있습니다.
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에 연결할 필요가 없습니다.
DB에 대한 새로운 히트가 아닌 기존 데이터 세트에서 책을 인스턴스화 할 수 있도록 책 객체의 속성을 수용하는 생성자를 작성해야합니다.
그래서:
건설자:
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 */ }
}
이데올로기 적 순도에서 다소 극단적 인 예를 들어 :
먼저, ID가 주어진 데이터베이스에서 T 형 객체를 검색 할 수있는 클래스의 인터페이스입니다.
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
이 수업은 사용합니다. a를 사용하는 다른 구현을 쓸 수 있습니다 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
적절한 시간에 해당 방법을 호출하십시오.
SQL Where Statement를 사용하여 데이터베이스 측에서 책의 가용성을 확인하지 않겠습니까?