简体   繁体   English

C# 使用映射器将 DataReader 映射到对象

[英]C# Using mapper to map a DataReader to an object

I've been struggling with getting ExpressMapper to map from a DataReader to a object (basically, Sqlite Rows -> Objects) .我一直在努力让 ExpressMapper 从 DataReader 映射到对象(基本上是 Sqlite Rows -> Objects)。 I've had success with AutoMapper, but found some other issues that got me looking for another map tool.我在 AutoMapper 上取得了成功,但发现了一些其他问题让我寻找另一个地图工具。

In AutoMapper I used the following code, but in ExpressMapper all string properties are NULL and the long prop is always 0, this indicates that the mapping is failing.在 AutoMapper 中我使用了以下代码,但在 ExpressMapper 中,所有字符串属性均为 NULL,并且 long 属性始终为 0,这表明映射失败。 Tried to look some examples for ExpressMapper but did not found any.试图查看 ExpressMapper 的一些示例,但没有找到任何示例。 Can you help?你能帮我吗? Also, are there any other mappers besides AutoMapper (and possibly ExpressMapper) that can help me achieve this scenario?此外,除了 AutoMapper(可能还有 ExpressMapper)之外,还有其他映射器可以帮助我实现这种情况吗?

Thanks!谢谢!

 public class ImportedFiles
{
    public Int64 Id { get; set; }
    public String FileName { get; set; }
    public String Hash { get; set; }

    public ImportedFiles()
    {

    }

}

private static void ReadImportedFiles()
    {
        var lst = ReadData<ImportedFiles>("SELECT * FROM ImportedFiles").ToList();
    }

 public static IEnumerable<T> ReadData<T>(string queryString)
        {
            using (var connection = new SQLiteConnection(ConnectionBuilder.ConnectionString))
            {
                connection.Open();
                using (var cmd = connection.CreateCommand())
                {
                    cmd.CommandText = queryString;
                    using (var reader = cmd.ExecuteReader())
                        if (reader.HasRows)
                            while (reader.Read())
                                yield return Mapper.Map<IDataRecord, T>(reader);
                }
            }
        }

are there any other mappers besides AutoMapper (and possibly ExpressMapper) that can help me achieve this scenario? 除了AutoMapper(可能还有ExpressMapper)之外,还有其他映射器可以帮助我实现这种情况吗?

Yes. 是。 Generally, they are called Object-Relational Mappers (shortened to O/RM or just ORM). 通常,它们称为对象关系映射器 (简称为O / RM或简称为ORM)。 There are many; 有许多; a couple of the most popular for the .NET framework are Entity Framework and NHibernate . .NET框架中最受欢迎的几个是Entity FrameworkNHibernate

I think you are using the wrong class of tool (object-to-object mappers) for the task at hand ( object-relational mapping ). 我认为您为当前的任务( 对象关系映射 )使用了错误的工具 (对象到对象映射器)。

Object-to-object mappers are designed for mapping between closely aligned, strongly-typed, data-containing classes, usually to save hand-writing mapping code. 对象到对象映射器设计用于在紧密对齐,强类型,包含数据的类之间进行映射,通常可以节省手写的映射代码。 They are not designed for mapping to or from more generic data containers like DataRow , or for dealing with other "plumbing" concerns that come into play when working with a relational database. 它们并非设计用于与诸如DataRow类的更通用的数据容器进行映射,也不能用于处理使用关系数据库时出现的其他“管道”问题。

ExpressMapper is capable to map to a DataRow. ExpressMapper能够映射到DataRow。 This should solves your issue. 这应该可以解决您的问题。

Just refactor your code to work with a DataRow. 只需重构您的代码即可使用DataRow。 And pre-register the mapping. 并预先注册映射。

So, if you write: 因此,如果您写:

yield return Mapper.Map<DataRow, T>(row);

And do the mappings (once per application) like I suggested: 并按照我的建议进行映射(每个应用程序一次):

        Mapper.Register<DataRow, ImportedFiles>()
            .Member(dest => dest.Id,
                    src => DBNull.Value == src["Id"] ? 0 : (double)src["Id"])
            .Member(dest => dest.FileName,
                    src => DBNull.Value == src["FileName"] ? String.Empty : (string)src["FileName"])
            .Member(dest => dest.Hash,
                    src => DBNull.Value == src["Hash"] ? String.Empty : (string)src["Hash"])
            ;

You're able to use it. 您可以使用它。


[Edited] [编辑]

In case you need to map more than one source (ie: more than one DataTable) then you could write a DataRowAdapter which will differentiate your mapping and let know ExpressMapper (or whatever ORM you want to use - this is appliable to all ORM) which data to expect in your DataRow. 如果您需要映射多个源(即:多个DataTable),则可以编写一个DataRowAdapter来区分您的映射并告知ExpressMapper(或您要使用的任何ORM-适用于所有ORM) DataRow中期望的数据。

Below a working example with your code. 下面是带有您的代码的工作示例。

yield return Mapper.Map<DataRowAdapter<T>, T>(new DataRowAdapter<T>(row));

DataRowAdapter class: DataRowAdapter类:

public class DataRowAdapter<T>
{
    DataRow _dataRow;

    public DataRowAdapter(DataRow dataRow)
    {
        _dataRow = dataRow;
    }

    public DataRow Current
    {
        get
        {
            return _dataRow;
        }
    }
}

And your new-brand mapping: 和您的新品牌映射:

     Mapper.Register<DataRowAdapter<ImportedFiles>, ImportedFiles>()
        .Member(dest => dest.Id,
                src => DBNull.Value == src.Current["Id"] ? 0 : (double)src.Current["Id"])
        .Member(dest => dest.FileName,
                src => DBNull.Value == src.Current["FileName"] ? String.Empty : (string)src.Current["FileName"])
        .Member(dest => dest.Hash,
                src => DBNull.Value == src.Current["Hash"] ? String.Empty : (string)src.Current["Hash"])
        ;

Done. 做完了

Example using SQLiteData reader to map the selected items to Object class List使用 SQLiteData 阅读器将所选项目映射到 Object 类 List 的示例

public static List<Object.Class> getObject()
    {
        List<Object.Class> list = new List<Object.Class>();
        var datareader = Database.getData();
        while (datareader.Read())
        {


            list.Add(item: new Object.Class(
               id: datareader.GetInt32(0),
            date: DateTime.Parse(datareader.GetString(6))
                )
        );


        }
        datareader.Close();

        return list;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM