代码之家  ›  专栏  ›  技术社区  ›  Jon Smock

如何编写返回实例集合的类方法

  •  4
  • Jon Smock  · 技术社区  · 16 年前

    我正在努力定义一个类方法来填充并返回实例集合。我不知道如何解决的问题是,我有自己的属性来填充。

    让我们用一个图书类的例子。我不希望代码直接设置(比如)一本书的可用性。我希望代码必须在Book实例上使用签出方法。所以我们有这样的东西:

    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,但我需要问一下。

    4 回复  |  直到 16 年前
        1
  •  2
  •   marijne    16 年前

    您可以创建一个受保护的构造函数,它直接填充私有属性。

        2
  •  2
  •   missaghi    16 年前

    foreach应该迭代已经实例化的对象列表,它们不需要连接到数据库。

    您需要创建一个接受Book对象属性的构造函数,这样您就可以从现有的一组数据中实例化一本书,而不是从新的数据库命中。

    所以:

    Constructor:

    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 */ }
    
    }
    
        3
  •  1
  •   Robert Rossney    16 年前

    例如,在意识形态的纯洁性上有点极端:

    首先,类的接口,它可以从给定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.Adapter 以使 Book.Create() 将能够从数据库中提取内容。

    我之所以说“思想纯洁”,是因为这种设计加强了一种相当严格的关注分离:在 类,它知道如何与数据库通信,甚至在那里 数据库。

    例如,下面是 IAdapter<书籍> :

    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);
       }
    }
    

    这个实现根本不使用数据库-在为 班级。

    注意,这两个类都维护一个私有的 List<Book> 财产。这保证了每次你打电话 创建() 用一个给定的身份证,你会得到相同的回报 实例。有一个论点可以证明这是 类-您将使静态私有化 列表<book> 属性 并编写逻辑使 Create 方法维护它。

    您使用相同的方法将数据推回到数据库-add Update , Delete Insert 方法到 IAdapter<T> 并在适配器类中实现它们, 在适当的时候调用这些方法。

        4
  •  0
  •   Fabian Vilers    16 年前

    为什么不使用SQL WHERE语句检查数据库端书籍的可用性?