NpgSQLdataReader GetOrdinal抛出异常..任何方式?

时间:2010-02-12 16:43:55

标签: c# datareader npgsql

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

由于我允许许多属性为null或使用DTO的默认值,因此我在填写prperty之前使用了一种方法来检查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有一个参数可以添加到连接字符串(Compatability)以支持此方法的向后兼容性,但是我从来没有这样做才能正常工作(由于形成连接错误,我总是得到一个例外串)。无论如何,我正在寻找更好的解决方法的建议。有没有更好的方法从datareader填充对象,甚至以某种方式解决异常问题?

1 个答案:

答案 0 :(得分: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 ticks
  • 第二个查询(与第一个相同): 1141K ticks

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

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

我使用的原始代码消耗了比使用限制在所需字段的方法多3倍的刻度。杀死它的重复。

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

这似乎很好,至少现在。可能会尝试寻找几个优化。 任何消化都将不胜感激!