2009-05-21 8 views
6

Dường như không có phương pháp Peek trên DataReader trong ado.net. Tôi muốn có thể thực hiện một số xử lý một lần trước khi tôi lặp qua đầu đọc của mình, và sẽ rất tuyệt khi có thể xem dữ liệu trong hàng đầu tiên mà không làm cho nó bị bỏ qua bởi lần lặp tiếp theo. cách tốt nhất để thực hiện điều này là gì?Làm cách nào để triển khai một hàm Peek() trên một DataReader?

Tôi đang sử dụng SqlDataReader, nhưng tốt nhất là triển khai sẽ càng chung càng tốt (ví dụ: áp dụng cho IDataReader hoặc DbDataReader).

Trả lời

5

tôi sẽ đề nghị một cái gì đó tương tự như giải pháp của Jason, nhưng sử dụng một wrapper mà thực hiện IDataReader thay vào đó, như vậy:

sealed public class PeekDataReader : IDataReader 
{ 
    private IDataReader wrappedReader; 
    private bool wasPeeked; 
    private bool lastResult; 

    public PeekDataReader(IDataReader wrappedReader) 
    { 
     this.wrappedReader = wrappedReader; 
    } 

    public bool Peek() 
    { 
     // If the previous operation was a peek, do not move... 
     if (this.wasPeeked) 
      return this.lastResult; 

     // This is the first peek for the current position, so read and tag 
     bool result = Read(); 
     this.wasPeeked = true; 
     return result; 
    } 

    public bool Read() 
    { 
     // If last operation was a peek, do not actually read 
     if (this.wasPeeked) 
     { 
      this.wasPeeked = false; 
      return this.lastResult; 
     } 

     // Remember the result for any subsequent peeks 
     this.lastResult = this.wrappedReader.Read(); 
     return this.lastResult; 
    } 

    public bool NextResult() 
    { 
     this.wasPeeked = false; 
     return this.wrappedReader.NextResult(); 
    } 

    // Add pass-through operations for all other IDataReader methods 
    // that simply call on 'this.wrappedReader' 
} 

Lưu ý rằng điều này đòi hỏi khá nhiều pass-through mã cho tất cả các thuộc tính không bị ảnh hưởng, nhưng lợi ích là nó là một trừu tượng chung chung mà có thể 'peek' tại bất kỳ vị trí nào trong tập hợp kết quả mà không cần chuyển tiếp về hoạt động 'đọc' tiếp theo.

Cách sử dụng:

using (IDataReader reader = new PeekDataReader(/* actual reader */)) 
{ 
    if (reader.Peek()) 
    { 
     // perform some operations on the first row if it exists... 
    } 

    while (reader.Read()) 
    { 
     // re-use the first row, and then read the remainder... 
    } 
} 

Lưu ý rằng mặc dù cuộc gọi mỗi 'Peek()' sẽ thực sự chuyển sang bản ghi tiếp theo nếu các hoạt động trước đó đã không còn là một 'Peek()'. Giữ sự đối xứng này với thao tác 'Đọc()' cung cấp một cách thực hiện đơn giản hơn và một API thanh lịch hơn.

+1

Ví dụ của bạn không hoạt động vì bản thân giao diện 'IDataReader' không chứa phương thức' .Peek' của bạn. Bạn nên nhập rõ ràng biến phạm vi sử dụng là 'PeekDataReader' hoặc sử dụng' var'. – julealgon

3

Bạn không cần phương thức Peek(). Bạn có thể thực hiện những gì bạn cần với vòng lặp Do While.

Vì vậy, thay vì

while(dr.read()) 
{ 
    ... do stuff 
} 

Bạn sẽ

dr.read(); 
... do stuff 

do 
{ 
    ... do stuff 
}while(dr.read()) 
+0

Peek() tương đối linh hoạt hơn nhiều so với phương pháp này vì có thể thực hiện nhiều lần trên cùng một DataReader, ở nhiều nơi, mà không phải chuyển kết quả "lần đầu tiên". –

+1

Đọc các giá trị DataReader không di chuyển nó về phía trước, phương thức Read() thực hiện nó. Bạn có thể đọc các giá trị nhiều lần tùy thích mà không cần di chuyển nó lên phía trước. Tôi không chắc Peek() sẽ thêm bất kỳ giá trị nào. Tôi có thể đã bỏ lỡ quan điểm của bạn. ???? –

+0

Điều này là hoàn toàn khả thi, nhưng tôi muốn tiêu thụ người đọc qua LINQ thay vì theo cách thủ công. –

4

Bạn có thể tạo một máy nhà nước theo dõi ú chế độ vs thường xuyên-mode. Có thể một cái gì đó như thế này (chỉ có thể quăng tất cả chúng vào một tệp duy nhất được gọi là Peeker.cs hoặc một cái gì đó tương tự):

Loại quá mức, nhưng tốt.

Để sử dụng nó, bạn sẽ chỉ làm như sau:

Peeker p = new Peeker(); 
. 
. 
. 
SomeDataReaderType dr = SomeCommandType.ExecuteReader(); 
. 
. 
. 
// To peek 
object[] myDataRow = p.OnRead(dr, true); 

// or not to peek 
object[] myDataRow = p.OnRead(dr, false); 

Sau đó, làm những gì bạn cần phải làm với hàng của bạn. Có thể có một cách tốt hơn so với sử dụng một mảng đối tượng, nhưng bạn có được điểm.

Chúc may mắn!

+0

Đây là nhiều hơn hoặc ít hơn những gì tôi đã đi. Có vẻ như tôi cần một lớp bao bọc để tôi có thể giữ thông tin trạng thái. Tôi không chắc chắn nếu nó có giá trị phức tạp, mặc dù. –

+0

Phụ thuộc vào tầm quan trọng của nó. Nó sẽ không mất quá nhiều mã để làm điều đó, nhưng nó sẽ mất một chút công việc (3 lớp nhỏ có khả năng). –

+0

Cũng làm cho 4 lớp nhỏ =) –