C# - 使用泛型将 IDataReader 映射到对象

发布于 2024-07-26 18:46:02 字数 705 浏览 3 评论 0原文

如何使用泛型将 DataReader 对象映射到类对象?

例如,我需要执行以下操作:

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

然后我需要像下面这样调用这个类方法:

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

请注意,Mapper 类应该能够映射由 T 表示的任何类型的对象。

How can I map a DataReader object into a class object by using generics?

For example I need to do the following:

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

And later I need to call this class-method like the following:

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

Note that, the Mapper - class should be able to map object of any type represented by T.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

柠北森屋 2024-08-02 18:46:02

我使用 ValueInjecter 为此,

我这样做:

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

你需要这个 ValueInjection 才能工作:

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

I use ValueInjecter for this

I'm doing like this:

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

you gonna need this ValueInjection for this to work:

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);
            }
        }
    }
╄→承喏 2024-08-02 18:46:02

好吧,我不知道它是否适合这里,但你可以使用yield关键字

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

Well, i don't know if it fits here, but you could be using the yield keyword

public static IEnumerable<T> MapObject(IDataReader dr, Func<IDataReader, T> convertFunction)
        {
            while (dr.Read())
            {
                yield return convertFunction(dr);
            }
        }
盗梦空间 2024-08-02 18:46:02

您可以使用我编写的 LateBinder 类: http://codecube.net/2008/12/ new-latebinder/

我写了另一篇关于用法的文章: http://codecube.net/2008/12/使用-the-latebinder/

You could use this LateBinder class I wrote: http://codecube.net/2008/12/new-latebinder/.

I wrote another post with usage: http://codecube.net/2008/12/using-the-latebinder/

陌伤浅笑 2024-08-02 18:46:02

这将很难做到,因为您基本上是在尝试将两个未知数映射在一起。 在您的通用对象中,类型是未知的,并且在您的数据读取器中,表是未知的。

所以我建议您创建某种列属性来附加到实体的属性。 然后查看这些属性并尝试在数据读取器中从这些属性中查找数据。

您最大的问题是,如果在阅读器中找不到某个属性,或者反之亦然,在实体中找不到阅读器中的某一列,会发生什么。

祝你好运,但如果你想做这样的事情,你可能需要一个 ORM 或至少需要某种 Active Record 实现。

This is going to be very hard to do for the reason that you are basically trying to map two unknowns together. In your generic object the type is unknown, and in your datareader the table is unknown.

So what I would suggest is you create some kind of column attribute to attach to the properties of you entity. And then look through those property attributes and try to look up the data from those attributes in the datareader.

Your biggest problem is going to be, what happens if one of the properties isn't found in the reader, or vice-versa, one of the columns in the reader isn't found in the entity.

Good luck, but if you want to do something like this, you probably want a ORM or at the very least some kind of Active Record implementation.

谢绝鈎搭 2024-08-02 18:46:02

我能立即想到的最简单的方法是提供一个 Func委托来转换每一列并构建您的书。

或者,如果您遵循一些约定,则可以通过反射来处理此问题。 例如,如果每列都使用相同的名称映射到结果对象中的属性,并且您将 Mapper 中的 T 限制为提供可构造的 T,则可以使用反射将每个属性的值设置为相应列中的值。

The easiest way I can think of offhand would be to supply a Func<T,T> delegate for converting each column and constructing your book.

Alternatively, if you followed some conventions, you could potentially handle this via reflection. For example, if each column mapped to a property in the resulting object using the same name, and you restricted T in your Mapper to providing a constructable T, you could use reflection to set the value of each property to the value in the corresponding column.

一杆小烟枪 2024-08-02 18:46:02

我认为您无法绕过以某种形式定义字段之间的关系。 看看这篇文章,特别注意映射是如何定义的,它可能对你有用。

http://www.c-sharpcorner.com/UploadFile/rmcochran/ beautiful_dal05212006130957PM/elegant_dal.aspx

I don't think you'll be able to get around defining the relationship between fields in some form. Take a look at this article and pay particular attention to how the mapping is defined, it may work for you.

http://www.c-sharpcorner.com/UploadFile/rmcochran/elegant_dal05212006130957PM/elegant_dal.aspx

花开柳相依 2024-08-02 18:46:02

不知道它在语法上

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;

    }
}

是否正确,但我希望你能明白。

what about following

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;

    }
}

Don't know if it is syntactically correct, but I hope u get the idea.

凝望流年 2024-08-02 18:46:02

使用 Fluent Ado.net 怎么样?

What about using Fluent Ado.net ?

恬淡成诗 2024-08-02 18:46:02

我建议您为此使用 AutoMapper

I would recommend that you'd use AutoMapper for this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文