2011-10-26 54 views
2

我有以下代碼形狀。看來我誤解了C#方法的返回值。一個「完整的」枚舉器如何被返回爲空的呢?爲什麼我成功讀取的Npgsql數據消失?

class ThingDoer 
{ 
    public NpgsqlDataReader DoQuery() 
    { 
     NpgsqlCommand c = new NpgsqlCommand(...); 
     NpgsqlDataReader dataread = c.ExecuteReader(); 
     return dataread; // Debugger confirms that six data are enumerable here. 
    } 
} 

... 

class OtherThing 
{ 
    public void higherLevelFunction() 
    { 
     NpgsqlDataReader result = myThingDoer.DoQuery(); 
     result.Read(); // No data! result's enumerable returns nothing! 
    } 
} 
+0

調試器如何「確認」這個?你在調試器中調用什麼?一個空的結果仍然有字段,但沒有行。另外,所有這些NpgsqlConnection在哪裏? –

+0

@Jon Hanna我已經消除了所有額外的工作,包括像連接這樣的世俗細節,以支持突出顯示實際問題。通過設置斷點,我能夠檢查返回前後讀取的數據。 –

回答

2

您不詳細說明您的連接來自何處。假設它的東西,如:

public NpgsqlDataReader DoQuery() 
{ 
    using(NpgsqlConnection = GetConnectionCode()) 
    { 
     NpgsqlCommand c = new NpgsqlCommand(...); 
     NpgsqlDataReader dataread = c.ExecuteReader(); 
     return dataread; 
    }//Connection closes at this using-scope being left because that triggers Dispose() 
} 

然後將其更改爲:

public NpgsqlDataReader DoQuery() 
{ 
    bool ownershipPassed = false; 
    NpgsqlConnection conn = GetConnectionCode(); 
    try 
    { 
     NpgsqlCommand c = new NpgsqlCommand(...); 
     NpgsqlDataReader dataread = c.ExecuteReader(CommandBehavior.CloseConnection); 
     ownershipPassed = true; 
     return dataread; 
    } 
    finally 
    { 
     if(!ownershipPassed)//only if we didn't create the reader than takes charge of the connection 
      conn.Dispose(); 
    } 
} 

然後在您使用的讀者,你必須將它部署到依次配置到數據庫的連接的基礎連接:

public void higherLevelFunction() 
{ 
    using(NpgsqlDataReader result = myThingDoer.DoQuery()) 
     result.Read(); 
} 
+0

啊!我明白你爲什麼問現在的連接。對不起,很sn。。 :-) –

+0

事實上,我明確表示關閉()連接,認爲它已經運行了。 –

+0

我並沒有把它看作是一種sn。。如果事情對我們每個人來說都是至關重要的,那麼決定某件事與問題無關。順便說一句,對於早期版本的Npgsql,調用Close()可以正常工作,但這實際上是一個缺陷,因爲它導致大型數據集被完全讀取而不是按需要進行讀取,從而影響了http:// npgsql的性能。 projects.postgresql.org/docs/manual/preloadScalabilty.html,但由於一些舊的代碼(包括NUnit測試之一)採取了你的方法,「預讀取器」命令字符串選項可以回到舊的方法... –

1
NpgsqlCommand c = new NpgsqlCommand(...); 
     NpgsqlDataReader dataread = c.ExecuteReader(); 

上述線是非常局部的方法DoQuery。因此,只要控件離開該方法,該方法內部創建的每個對象都會失去其作用域。因此,您將丟失數據,因爲它是您在調用方法中引用的引用類型。

+0

如何避免丟失物體? –

+0

使連接對象成爲類變量。這樣它就不會失去它的範圍。即使與DataReader一樣,您也可以在需要時實例化它,我的意思是當您可以使用DoQuery時,然後將它初始化爲新的SqlCommand(),但讓這些變量位於類範圍中。任何你在消費者代碼中創建DoQuery的類對象的方式,所以它的好! – Zenwalker

+0

不,你當然可以從方法返回一個NpgsqlDataReader。你需要確保NpgsqlConnection沒有關閉(最好通過使用CommandBehaviour.CloseConnection來確保它最終關閉了閱讀器)。他們也可能會關閉他們的連接(這個問題沒有提到),所以你可能在問題的正確軌道上,但即使這樣,範圍本身也不是問題。 –

相關問題