1

我为我通常在项目的 DAL 中使用的一堆方法构建了一个围绕 NpgSQL 的包装器。其中两个,我通常用来直接从 DataReader 填充 DTO。通常在填充辅助方法中,我将实例化 DTO 并遍历将 Datareader 的数据映射到相应属性的属性。填充方法大部分时间都会生成。

由于我允许许多属性为空或使用 DTO 的默认值,因此我使用了一种方法来检查 dataReader 的数据是否对属性有效,然后再填写属性。所以我将有一个 IsValidString("fieldname") 和一个 DRGetString("fieldname") 方法,如下所示:

public bool IsValidString(string fieldName)
{
        if (data.GetOrdinal(fieldName) != -1
            && !data.IsDBNull(data.GetOrdinal(fieldName)))
            return true;
        else
            return false;
}

public string DRGetString(string fieldName)
{
        return data.GetString(data.GetOrdinal(fieldName));
}

我的填充方法被委托给执行查询的任何方法,如下所示:

public static object FillObject(DataParse<PostgreSQLDBDataParse> dataParser)
{
     TipoFase obj = new TipoFase();   

     if (dataParser.IsValidInt32("T_TipoFase"))
        obj.T_TipoFase = dataParser.DRGetInt32("T_TipoFase");

     if (dataParser.IsValidString("NM_TipoFase"))
        obj.NM_TipoFase = dataParser.DRGetString("NM_TipoFase");

            //...rest of the properties .. this is usually autogenerated by a T4 template

     return obj;
}

这在 NpgSQL pre 2.02 中工作得很好。. 当调用 GetOrdinal 方法时,如果 dataReader 中不存在该字段,我会简单地返回 -1。在 IsValidString() 中很容易返回 false 并直接跳到下一个属性。检查不存在的字段对性能的影响几乎可以忽略不计。

不幸的是,当字段不存在时,对 NpgSQL 的更改会使 GetOrdinal 抛出异常。我有一个简单的解决方法,我将代码包装在 try /catch 中并在 catch 中抛出 false。但是我能感觉到性能受到了打击,尤其是当我进入调试模式时。填写一长串需要几分钟。

据推测,NpgSQL 有一个可以添加到连接字符串(兼容性)的参数以支持此方法的向后兼容性,但我从来没有让它正常工作(由于连接字符串格式错误,我总是遇到异常)。无论如何,我正在寻找更好的解决方法的建议。有什么更好的方法可以从数据读取器中填充对象,甚至可以以某种方式解决异常问题?

4

1 回答 1

0

我已经为我的问题创建了一个解决方案,不需要很大的改变,并且呈现出有趣的性能(或者看起来如此)。可能只是一个新的解析库/包装器。

基本上,我将遍历 dataReader 的字段,并将每个字段复制到一个 Collection(在我的例子中是一个 List)。然后我将检查有效数据,如果认为有效,我会将数据复制到对象的属性中。

所以我会有:

public class ParserFields
{
    public string FieldName { get; set; }
    public Type FieldType { get; set; }
    public object Data { get; set; }
}

我将使用以下方法填充对象:

public static object FillObjectHashed(DataParse<PostgreSQLDBDataParse> dataParser)
    {
        //The the Field list with field type and data
        List<ParserFields> pflist = dataParser.GetReaderFieldList(); 

        //create resulting object instance
        CandidatoExtendido obj = new CandidatoExtendido();

        //check for existing field and valid data and create object
        ParserFields pfdt = pflist.Find(objt => objt.FieldName == "NS_Candidato");
        if (pfdt != null && pfdt.FieldType == typeof(int) && pfdt.Data.ToString() != String.Empty)
            obj.NS_Candidato = (int)pfdt.Data;

        pfdt = pflist.Find(objt => objt.FieldName == "NM_Candidato");
        if (pfdt != null && pfdt.FieldType == typeof(string) && pfdt.Data.ToString() != String.Empty)
            obj.NM_Candidato = (string)pfdt.Data;

        pfdt = pflist.Find(objt => objt.FieldName == "Z_Nasc");
        if (pfdt != null && pfdt.FieldType == typeof(DateTime) && pfdt.Data.ToString() != String.Empty)
            obj.Z_Nasc = (DateTime)pfdt.Data;

        //...

        return obj;
    }

我对我的变化进行计时,以查看差异。进行了搜索,返回了 612 个结果。首先,我两次查询数据库也考虑到第一次运行查询和随后与缓存相关的差异(以及非常重要的差异)。我的 FillObject 方法只是创建了要添加到结果列表中的所需对象的新实例。

  • 对对象实例列表的第一次查询:2896K滴答声
  • 第二次查询(与第一次相同):1141K滴答声

然后我尝试使用以前的填充对象

  • 到所需对象的列表,填充返回数据或默认值,检查所有对象属性:3323K滴答
  • 要列出所需对象,仅检查搜索中返回的对象属性:1127K滴答
  • 要列出所需对象,使用查找列表,仅检查返回的字段:1097K滴答
  • 要列出所需对象,使用查找列表,检查所有字段(减去一些嵌套属性):1107K滴答声

与使用仅限于所需字段的方法相比,我使用的原始代码消耗了近 3 倍的滴答声。杀死它的地方。

使用 fillobject 方法的新代码,与仅检查所需字段相比,检查不存在的字段的开销极小。

这似乎工作得很好,至少现在是这样。可能会尝试寻找一些优化。任何建议将不胜感激!

于 2010-03-04T00:52:46.440 回答