2009-07-09 38 views
10

Làm cách nào để ánh xạ đối tượng DataReader vào đối tượng lớp bằng cách sử dụng Generics?C# - IDataReader để ánh xạ đối tượng bằng cách sử dụng Generics

Ví dụ tôi cần phải làm như sau:

public class Mapper<T> 
    { 
     public static List<T> MapObject(IDataReader dr) 
     { 
      List<T> objects = new List<T>(); 

      while (dr.Read()) 
      { 
       //Mapping goes here... 
      } 

      return objects; 
     } 
    } 

Và sau đó tôi cần phải gọi đây là đẳng cấp phương pháp như sau:

IDataReder dataReader = DBUtil.Fetchdata("SELECT * FROM Book"); 

List<Book> bookList = Mapper<Book>.MapObject(dataReder); 

foreach (Book b in bookList) 
{ 
    Console.WriteLine(b.ID + ", " + b.BookName); 
} 

Lưu ý rằng, các Mapper - lớp nên có thể ánh xạ đối tượng thuộc bất kỳ loại nào được đại diện bởi T.

+0

Một đề xuất - hãy đọc vào một tài khoản số có thể thu được bằng IE với thu nhập lợi nhuận. –

+0

// ánh xạ đến đây, chính xác những gì tôi đã cho bạn thấy trong câu trả lời của tôi, bạn có thể ánh xạ bất kỳ đối tượng nào tới trình đọc dữ liệu (chính xác hơn: tiêm các giá trị từ IDataReader vào một đối tượng BẤT CỨ LOẠI) – Omu

+0

Tại sao bạn không sử dụng dành riêng cho ORM sau đó? Một vi-ORM như Dapper có vẻ là một phù hợp tốt ở đây. – nawfal

Trả lời

3

tôi sử dụng ValueInjecter cho điều này

tôi đang làm như thế này:

while (dr.Read()) 
    { 
     var o = new User(); 
     o.InjectFrom<DataReaderInjection>(dr); 
     yield return o; 
    } 

bạn sẽ cần ValueInjection này để làm việc này:

public class DataReaderInjection : KnownSourceValueInjection<IDataReader> 
    { 
     protected override void Inject(IDataReader source, object target, PropertyDescriptorCollection targetProps) 
     { 
      for (var i = 0; i < source.FieldCount; i++) 
      { 
       var activeTarget = targetProps.GetByName(source.GetName(i), true); 
       if (activeTarget == null) continue; 

       var value = source.GetValue(i); 
       if (value == DBNull.Value) continue; 

       activeTarget.SetValue(target, value); 
      } 
     } 
    } 
+0

Ở đâu đó có thư viện tiêm chích thông thường và hữu ích nào không? –

+0

@PavelHodek không có thư viện nhưng có rất nhiều giải pháp demo chính của Valueinjecter và cũng có trong các trang codeplex – Omu

+0

Rất ít điều. 1) Bạn đang sử dụng sự phản chiếu để đặt giá trị, điều này không tốt cho hiệu suất. Đi biểu lộ lộ trình. 2) DataReaderInjection và KnownSourceValueInjection ở đâu trong thư viện của bạn? Tôi nghĩ rằng bạn đã thay đổi tên kể từ câu trả lời này? 3) Là nó bằng cách sử dụng phản ánh đằng sau hậu trường mỗi lần trong khi đọc.Đọc vòng lặp để có được tên tài sản? Tôi hy vọng không, nhưng không thể thuyết phục bản thân mình mà không nhìn thấy lớp KnownSourceValueInjection. – nawfal

2

Vâng, tôi không biết liệu nó có phù hợp ở đây hay không, nhưng bạn có thể sử dụng từ khóa lợi nhuận

public static IEnumerable<T> MapObject(IDataReader dr, Func<IDataReader, T> convertFunction) 
     { 
      while (dr.Read()) 
      { 
       yield return convertFunction(dr); 
      } 
     } 
+0

+1 Sử dụng thú vị DI. Nó sẽ là tốt đẹp để có loại T cung cấp việc thực hiện convertFunction là tốt. : D –

+0

Đây là DI đẹp và nó có thể được kết hợp với giải pháp của Omu. –

1

này sẽ là rất khó thực hiện vì lý do mà bạn đang cố gắng cơ bản để lập bản đồ hai ẩn số với nhau. Trong đối tượng chung của bạn, kiểu không xác định và trong bảng dữ liệu của bạn, bảng này không xác định.

Vì vậy, những gì tôi muốn đề nghị là bạn tạo một số loại thuộc tính cột để đính kèm vào các thuộc tính của thực thể bạn. Và sau đó xem xét các thuộc tính thuộc tính đó và cố tìm kiếm dữ liệu từ các thuộc tính đó trong trình quản lý dữ liệu.

Vấn đề lớn nhất của bạn sẽ xảy ra, điều gì xảy ra nếu một trong các thuộc tính không được tìm thấy trong trình đọc hoặc ngược lại, một trong các cột trong trình đọc không được tìm thấy trong thực thể.

Chúc may mắn, nhưng nếu bạn muốn làm điều gì đó như thế này, bạn có thể muốn có ORM hoặc ít nhất là một số loại triển khai Active Record.

+0

nhìn vào câu trả lời của tôi, nó không phải là khó :), và không có thuộc tính yêu cầu – Omu

1

Cách dễ nhất mà tôi có thể nghĩ là sẽ cung cấp cho đại biểu Func<T,T> để chuyển đổi từng cột và tạo sách của bạn.

Hoặc, nếu bạn theo một số quy ước, bạn có khả năng xử lý việc này thông qua phản ánh. Ví dụ, nếu mỗi cột ánh xạ tới một thuộc tính trong đối tượng kết quả sử dụng cùng tên, và bạn giới hạn T trong Mapper của bạn để cung cấp T có thể xây dựng, bạn có thể sử dụng sự phản chiếu để đặt giá trị của mỗi thuộc tính thành giá trị trong cột tương ứng .

1

những gì về sau

abstract class DataMapper 
{ 
    abstract public object Map(IDataReader); 
} 

class BookMapper : DataMapper 
{ 
    override public object Map(IDataReader reader) 
    { 
     ///some mapping stuff 
     return book; 
    } 
} 

public class Mapper<T> 
{ 
    public static List<T> MapObject(IDataReader dr) 
    { 
     List<T> objects = new List<T>(); 
     DataMapper myMapper = getMapperFor(T); 
     while (dr.Read()) 
     { 
      objects.Add((T)myMapper(dr)); 
     } 

     return objects; 
    } 

    private DataMapper getMapperFor(T myType) 
    { 
     //switch case or if or whatever 
     ... 
     if(T is Book) return bookMapper; 

    } 
} 

Không biết nếu nó là đúng cú pháp, nhưng tôi hy vọng u được ý tưởng.

+0

Bạn có thể tránh các điều kiện khác và dựa vào đa hình miễn là lớp Sách thực hiện một số Func . – nawfal

1

Tôi muốn giới thiệu mà bạn muốn sử dụng AutoMapper cho việc này.

Các vấn đề liên quan