Почему происходит сбой вызова SqlCeCommand ExecuteReader?
Я адаптировал код ниже из "Microsoft .NET Compact Framework" Wigley и Wheelwright:
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() показывает это:
... а есть такая таблица:
Я вижу "Сделано в pt 1", но не "Сделано в pt 2", поэтому при вызове ExecuteReader() должно произойти сбой - но почему?
Это сообщение об ошибке я вижу:
Я скопировал NETCFv35.Messages.EN.wm.cab в папку на контроллере, где находится.exe, но он все еще показывает то же сообщение об ошибке, что и выше. Нужно ли поставить его в другом месте или установить / настроить как-то? Двойное нажатие ничего не сделало, но показало мне файлы, которые были внутри.
compactf SqlCeCommand ExecuteReader SqlCeConnection SqlCeDataReader windowsce C#
ОБНОВИТЬ
Основываясь на том, что я здесь прочитал, я поместил путь / имя файла в одинарные кавычки, например:
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 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 Reference как внутреннее исключение.???
ОБНОВЛЕНИЕ 4
Так как я вижу "Сделано в пт 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
... Конн и Кри должны быть в порядке; так почему вызов open на conn приводит к 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
Должны ли база данных и источник данных действительно быть одним и тем же?
ОБНОВЛЕНИЕ 6
Возможно, у меня уже есть "живое" (глобальное) соединение с базой данных, созданной в другом месте / ранее; может ли это привести к взрыву второго соединения?
Я знаю [,] это плохой дизайн, но пока "это то, что есть"
ОБНОВЛЕНИЕ 7
Я никогда не получаю ответа на призыв к Open - он взрывается сильнее, чем Джордж Бретт, пойманный с кедровой смолой на его летучей мыши. Вот соответствующая часть кода:
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
Окно сообщения, которое отображается (перед "Сделано как раз перед conn.Open()"):
Затем я вижу "Попробую открыть", затем NRE.
ОБНОВЛЕНИЕ 8
Ниже приведен не только сам код, но и код, который его вызывает. Это возможная проблема повторного ввода кода? Может ли второй цикл foreach в SendInventoryData() вызывать 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"
INV12262006091415 существует в HHSDB003.SDF
ОБНОВЛЕНИЕ 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 здесь: Как я могу распространить сообщение об ошибке "80004005 Произошло нарушение совместного доступа к файлу…". Ошибка в базе данных SQL Server CE?
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();
}