【问题标题】:Why is this SqlCeCommand ExecuteReader call failing?为什么这个 SqlCeCommand ExecuteReader 调用失败?
【发布时间】:2014-11-13 11:16:39
【问题描述】:

我从 Wigley 和 Wheelwright 的“Microsoft .NET Compact Framework”改编了下面的代码:

SqlCeConnection cn = new SqlCeConnection(@"Data Source=\My Documents\Traffic.sdf");
String sSQL= "SELECT CarID, Reg, Location FROM Cars");
SqlCeCommand cmdSelect = new SqlCeCommand(sSQL, cn);
cmdSelect.CommandType = CommandType.Text;
SqlCeDataReader dtr = cmdSelect.ExecuteReader(CommandBehavior.Default); // It's "cmd." instead of "cmdSelect." in the book, but that doesn't compile
while (dtr.Read())
{
    ListViewItem item = new ListViewItem(dtr.GetInt32(0).ToString());
    item.SubItems.Add(dtr.GetString(1));
    item.SubItems.Add(dtr.GetString(2));
    listViewCars.Items.Add(item);
}

...所以我的代码是这样的:

    private String getDataAsXMLFromTable(String tableName, String siteNum)
    {
        String strXML;
        StringBuilder sbXML = new StringBuilder();

        String lineId;
        String refNum;
        String upcCode;
        String desc;
        String dept;
        String vendorId;
        String upcPackSize;
        String Id;
        String packSize;
        String unitCost;
        String unitList;
        String unitQty;
        String newItem;

        String paddedSiteNum = Prepad(3, siteNum); // this turns "3" into "003" etc.
        String conStr = String.Format(@"Data Source=\My Documents\HHSDB{0}.sdf", paddedSiteNum);
        MessageBox.Show(String.Format("conStr is {0}", conStr));
        SqlCeConnection cn = new SqlCeConnection(conStr);
        String qry = String.Format("SELECT * FROM {0}", tableName);
        MessageBox.Show(String.Format("qry is {0}", qry));
        SqlCeCommand cmdSelect = new SqlCeCommand(qry, cn);
        MessageBox.Show("Made it to pt 1"); // <= I see this
        cmdSelect.CommandType = CommandType.Text;
        SqlCeDataReader dtr = cmdSelect.ExecuteReader(CommandBehavior.Default);
        MessageBox.Show("Made it to pt 2"); // <= I don't see this
        try
        {
            while (dtr.Read())
            {
                lineId = dtr["line_id"].ToString(); // Wiggly uses dtr.GetString(1); would then 
have to use GetX()...
                refNum = dtr["ref_no"].ToString();
                upcCode = dtr["upc_code"].ToString();
                desc = dtr["description"].ToString();
                dept = dtr["department"].ToString();
                vendorId = dtr["vendor_id"].ToString();
                upcPackSize = dtr["upc_pack_size"].ToString();
                Id = dtr["id"].ToString();
                packSize = dtr["pack_size"].ToString();
                unitCost = dtr["unit_cost"].ToString();
                unitList = dtr["unit_list"].ToString();
                unitQty = dtr["unit_qty"].ToString();
                newItem = dtr["new_item"].ToString();
                strXML = String.Format("<INV><line_id>{0}</line_id><ref_no>{1}</ref_no><upc_code>
{2}</upc_code><description>{3}</description><department>{4}</department><vendor_id>{5}
</vendor_id><upc_pack_size>{6}</upc_pack_size><id>{7}</id><pack_size>{8}</pack_size><unit_cost>{9}
</unit_cost><unit_list>{10}</unit_list><unit_qty>{11}</unit_qty><new_item>{12}</new_item></INV>", 
                    lineId, refNum, upcCode, desc, dept, vendorId, upcPackSize, Id, packSize,
                    unitCost, unitList, unitQty, newItem);
                sbXML.Append(strXML);

            }
        }
        catch (Exception ex)
        {
            SSCS.ExceptionHandler(ex, "frmCentral.getDataAsXMLFromTable()");
        }
        return String.Format("<Command>{0}</Command>", sbXML.ToString());
    }

我尝试访问的数据库位于手持设备的“我的文档”文件夹中,名为“HHSDB003.sdf”

我的第一个 MessageBox.Show() 显示了这个:

...这确实是数据库所在的位置:

我的第二个 MessageBox.Show() 显示了这个:

...还有这样一张桌子:

我看到“Made it to pt 1”,但没有看到“Made it to pt 2”,所以它在调用 ExecuteReader() 时肯定失败了 - 但为什么?

这是我看到的错误消息:

我将 NETCFv35.Messages.EN.wm.cab 复制到手持设备上 .exe 所在的文件夹中,但它仍然显示与上述相同的错误消息。我是否需要将它放在其他地方或以某种方式安装/设置它? 2 次单击它并没有做任何事情,只是向我显示其中的文件。

compactf SqlCeCommand ExecuteReader SqlCeConnection SqlCeDataReader windowsce c#

更新

根据我阅读的here,我将路径/文件名放在单引号中,如下所示:

String conStr = String.Format(@"Data Source='\My Documents\HHSDB{0}.sdf'", paddedSiteNum);

...但没有区别。

更新 2

根据答案,我将代码更改为:

try
{
    . . .
    string connStr = "Data Source=\"\\My Documents\\HHSDB003.SDF\"";
    MessageBox.Show(String.Format("connStr is {0}", connStr));
    try
    {
        SqlCeConnection conn = new SqlCeConnection(connStr);
        String qry = String.Format("SELECT * FROM {0}", tableName);
        MessageBox.Show(String.Format("qry is {0}", qry));
        SqlCeCommand cmdSelect = new SqlCeCommand(qry, conn);
        MessageBox.Show("Made it to pt 1"); // <= I see this
        cmdSelect.CommandType = CommandType.Text;
        conn.Open(); // <= I was missing this
        MessageBox.Show("Made it to pt 2"); // <= I don't see this
        SqlCeDataReader dtr = cmdSelect.ExecuteReader(CommandBehavior.Default);
        . . .
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

...但是在看到“Made it to pt 1”后我得到了一个例外 - 我从来没有看到“Made it to pt 2”

从 catch 块显示的异常消息不显示任何内容/空字符串。

在手持设备的我的文档文件夹中有一个名为 HHSDB003.SDF 的数据库,它确实包含一个名为 ~ 的表;那么我在这里还缺少什么?

更新 3

我把 catch 块改成了这样:

catch (Exception ex)
{
    MessageBox.Show(String.Format("inner ex is {0}", ex.InnerException.ToString()));
}

...现在将 Null 引用异常视为内部异常。 ???

更新 4

因为我在这里看到“Made it to pt 1”:

string connStr = "Data Source=\"\\My Documents\\HHSDB003.SDF\"";
String qry = String.Format("SELECT * FROM {0}", tableName);

MessageBox.Show(String.Format("connStr is {0}", connStr));
try
{
    SqlCeConnection conn = new SqlCeConnection(connStr);
    SqlCeCommand cmdSelect = new SqlCeCommand(qry, conn);
    MessageBox.Show("Made it to pt 1"); // <= I see this
    cmdSelect.CommandType = CommandType.Text;
    conn.Open(); // <= I was missing this

...conn 和 qry 必须没问题;那么为什么在 conn 上调用 open 会导致 NRE?

更新 5

我添加了这段代码来查看 SqlCeConnection 的 Database 和 DataSource 属性的值:

MessageBox.Show(
    String.Format("db is {0}; data source is {1}", conn.Database, conn.DataSource));
// This should be redundant, but getting an NRE on the Open call...
conn.ConnectionString = connStr;

...我明白了:

db is \My Documents\HHSDB003.SDF
data source is  \My Documents\HHSDB003.SDF

Database 和 DataSource 真的应该是一回事吗?

更新 6

我可能已经与其他地方/以前建立的数据库建立了“实时”(全局)连接;这会导致第二个连接崩溃吗?

我知道[,]这是一个糟糕的设计,但现在“就是这样”

更新 7

我从来没有接受过公开赛的呼吁——它比乔治·布雷特 (George Brett) 的球拍上的松焦油炸得更热。这是代码的相关部分:

string connStr = String.Format("Data Source=\"\\My Documents\\HHSDB{0}.SDF\"", paddedSiteNum);
String qry = String.Format("SELECT * FROM {0}", tableName);
MessageBox.Show(String.Format("connstr is {0}; qry is {1}", connStr, qry));
SqlCeConnection conn;
SqlCeCommand cmdSelect;
try
{
    conn = new SqlCeConnection(connStr);
    cmdSelect = new SqlCeCommand(qry, conn);
    cmdSelect.CommandType = CommandType.Text;
    MessageBox.Show(
        String.Format("db is {0}; data source is {1}, conn string is {2}", conn.Database, conn.DataSource, conn.ConnectionString));
    conn.ConnectionString = connStr;
    MessageBox.Show("Made it just before conn.Open()"); // <= I always see this
    if ((null != conn) && (!conn.State.Equals(ConnectionState.Open)))
    {
        MessageBox.Show("Will try to Open");
        conn.Open();
    }
    MessageBox.Show("Made it just after conn.Open()"); // <= I never see this; the NRE steals the show

显示的消息框(在“Made it just before conn.Open()”之前)是:

然后我看到“将尝试打开”,然后是 NRE。

更新 8

下面不仅是代码本身,还有调用它的代码。这是一个可能的代码重入问题吗? SendInventoryData() 中的第二个 foreach 循环是否会调用 getDataAsXMLFromTable() 而之前对 getDataAsXMLFromTable() 的调用尚未完成? 似乎并非如此,因为我从来没有看到“在 conn.Open() 之后完成它”——甚至一次都没有。看来如果这是问题,我至少会看到一次......

private void mnuSendINV_Click(object sender, EventArgs e)
{
    // TODO: Remove after testing; "hijacking" this to query and send the file directly
    SendInventoryData();
    return;

private void SendInventoryData()
{
    String siteNum = String.Empty;
    ArrayList sbInventories = new ArrayList();
    foreach (String tbl in listboxWork.Items)
    {
        // Ignore DSD tables; just get INV tables
        if (tbl.IndexOf("DSD") >-1) continue;
        String tblName = getTableNameForInventoryName(tbl);
        siteNum = getSiteNumberFromInventoryName(tbl);
        sbInventories.Add(tblName);
    }
    foreach (string tbl in sbInventories) 
    {
        string strData = getDataAsXMLFromTable(tbl, "003"); 
        string fileName = getINVFileName(siteNum); 
        String uri = String.Format("http://192.168.125.50:21608/api/inventory/sendXML/duckbill/platypus/{0}", fileName);
        RESTfulMethods rm = new RESTfulMethods();
        rm.CreateRequestNoCredentials(uri, RESTfulMethods.HttpMethods.POST, strData, "application/xml"); 
    }
}

private String getDataAsXMLFromTable(String tableName, String siteNum)
{
    string xmlOutput = String.Empty;
    // data/xml fields
    String lineId;
    String refNum;
    . . .
    String newItem;

    String paddedSiteNum = Prepad(3, siteNum);
    string connStr = String.Format("Data Source=\"\\My Documents\\HHSDB{0}.SDF\"", paddedSiteNum);
    String qry = String.Format("SELECT * FROM {0}", tableName);
    MessageBox.Show(String.Format("connstr is {0}; qry is {1}", connStr, qry));
    SqlCeConnection sqlceConn;
    SqlCeCommand sqlceCmd;
    try
    {
        sqlceConn = new SqlCeConnection(connStr);
        sqlceCmd = new SqlCeCommand(qry, sqlceConn);
        sqlceCmd.CommandType = CommandType.Text;
        MessageBox.Show("Made it just before conn.Open()"); // <= I see this
        if ((null != sqlceConn) && (!sqlceConn.State.Equals(ConnectionState.Open)))
        {
            MessageBox.Show("Will try to Open"); // <= I see this
            sqlceConn.Open();
        }
        MessageBox.Show("Made it just after conn.Open()"); // <= I don't see this/make it to here; I see the NRE instead
        SqlCeDataReader dtr = sqlceCmd.ExecuteReader(CommandBehavior.Default);
        XmlDocument doc = new XmlDocument();// Create the XML Declaration, and append it to XML document
        XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", null, null);
        doc.AppendChild(dec);// Create the root element
        XmlElement root = doc.CreateElement("Command");
        doc.AppendChild(root);

        try
        {
            while (dtr.Read())
            {
                // outer INV
                XmlElement invRec = doc.CreateElement("INV");

                // Line ID
                lineId = dtr["line_id"].ToString();
                XmlElement _lineId = doc.CreateElement("line_id");
                _lineId.InnerText = lineId;
                invRec.AppendChild(_lineId);

                // Ref Num
                refNum = dtr["ref_no"].ToString();
                XmlElement _refNum = doc.CreateElement("ref_no");
                _refNum.InnerText = refNum;
                invRec.AppendChild(_refNum);

                . . .

                // New Item
                newItem = dtr["new_item"].ToString();
                XmlElement _new_item = doc.CreateElement("new_item");
                _new_item.InnerText = newItem;
                invRec.AppendChild(_new_item);

                root.AppendChild(invRec);
            }
        }
        finally
        {
            xmlOutput = doc.OuterXml;
            dtr.Close();
            if (sqlceCmd.Connection.State == ConnectionState.Open)
            {
                sqlceCmd.Connection.Close();
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(String.Format("inner ex is {0}", ex.InnerException.ToString()));
        SSCS.ExceptionHandler(ex, "frmCentral.getDataAsXMLFromTable()");
    }
    return xmlOutput;
} //getDataAsXMLFromTable

注意:使用此代码,我看到了:

0) "connstr is Data Source="\My Documents\HHSDB003.SDF"; qry is SELECT * FROM INV12262006091415"
1) "Made it just before conn.open"
2) "Will try to open"
3) "Exception: Null Reference Exception"

HHSDB003.SDF 中确实存在INV12262006091415

更新 9

我尝试将 getDataAsXMLFromTable() 封装在一个锁中:

lock (this)
{
    . . .
}

这没有帮助;这也没有:

public class HHSUtils
{       
    public static bool InGetDataAsXMLFromTable;

private String getDataAsXMLFromTable(String tableName, String siteNum)
{
    if (HHSUtils.InGetDataAsXMLFromTable) return String.Empty;
    HHSUtils.InGetDataAsXMLFromTable = true;
    . . .
    HHSUtils.InGetDataAsXMLFromTable = false;
    return xmlOutput;
}

现在奖励 100 个。

更新 10

在此处查看更新 3:How can I circument the "80004005 There is a file sharing violation...." err msg on a SQL Server CE database?

【问题讨论】:

标签: sql-server-ce compact-framework windows-ce executereader sqlcedatareader


【解决方案1】:

你忘记打开连接了。

string connString = "Data Source=\"\\My Documents\\HHSDB003.sdf\"";
string query = "SELECT * FROM MyTable";

SqlCeConnection conn = new SqlCeConnection(connString);
SqlCeCommand cmd = new SqlCeCommand(query, conn);

conn.Open();  // <--- THIS
SqlCeDataReader rdr = cmd.ExecuteReader();

try
{
    // Iterate through the results
    while (rdr.Read())
    {
    }
}
finally
{
    // Always call Close when done reading
    rdr.Close();
    // Always call Close when done reading
    conn.Close();
}

【讨论】:

  • 谢谢;我这个星期一去捷克,如果成功的话,给你50分。奇怪的是,书中的代码也缺少了那个重要的部分。再说一次,它显然没有经过实际测试,因为其中一个变量名的拼写不同(一次一种方式,其他地方另一种方式)。
  • 您在代码中的哪个位置调用 Open?获得 NRE 的唯一方法是在创建之前尝试打开它。
  • 如更新4所示,我先创建SqlCeConnection,然后打开它。
  • 我悲伤的最终原因似乎是 iexplore.exe 的流氓/损坏/臃肿实例破坏了工作(杀死它解决了问题,包括这个),但我绝对需要 Open( ) 打电话,所以我给你赏金 - 不要把它花在一个地方!
猜你喜欢
  • 2020-09-13
  • 2012-03-14
  • 1970-01-01
  • 1970-01-01
  • 2016-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多