Как база данных SQL Server CE может быть одновременно подключена и не подключена?

У меня есть база данных SQL Server CE в моем приложении Windows CE. Я вижу это (HHS.sdf) в моем проекте в обозревателе серверов:

... но папки Columns для таблиц не будут расширяться; щелкнув по ним, я получу:

Свойство path для HHS.sdf гласит:

Data Source=Mobile Device\Program Files\hhs\HHS.sdf

Если путь неверен, почему Server Explorer вообще показывает мне базу данных? Если я создаю новое соединение в обозревателе сервера (выбрав "Добавить соединение..." в контекстном меню "Соединения данных"), я могу перейти к файлу.SDF на устройстве (\Program Files\hhs), проверить соединение в диалоговое окно "Добавить соединение":

... и получить подтверждение "Проверка соединения выполнена успешно".

Но во время выполнения, при попытке заполнить одну из таблиц:

var dt = new DataTable();
dt.Columns.Add(new DataColumn("Id", typeof(Int32)));
dt.Columns.Add(new DataColumn("DeptNumber", typeof(Int32)));
dt.Columns.Add(new DataColumn("DeptName", typeof(string)));

foreach (HHSUtils.Department dept in depts)
{
    try
    {
        dt.Rows.Add(dept.Id, dept.DeptNumber, dept.DeptName);
        countAdded++;
    }
    catch (Exception ex)
    {
        MessageBox.Show(string.Format("deptId == {0}, deptNumber == {1},  
          deptName == {2} ({3})", dept.Id, dept.DeptNumber, dept.DeptName, ex.Message));
    }
}
// Now move it all into the table
using (var bc = new SqlCeBulkCopy(dataSource))
{
    bc.DestinationTableName = "Departments";
    bc.WriteToServer(dt);
}

... Я получаю, "Исходный столбец 'DEPTNUM' не существует, и пункт назначения не допускает нулевые значения" в строке WriteToServer().

Оценивая "dt" в отладчике, я вижу, что свойство DataSet имеет красный значок "ошибка" и говорит: "не удалось оценить выражение"; то же самое касается свойств "Сайт" и "XMLTest"; Свойство dataSet (в отличие от DataSet) имеет значение null.

Слово "DEPTNUM" нигде не встречается в исходном коде клиента, равно как и в исходном коде сервера...

Тот же код для таблицы InventoryItems выполняется без сообщения об ошибке (но в обозревателе сервера столбцы по-прежнему чрезвычайно застенчивы).

Я создаю таблицы следующим образом:

// Got this from http://stackru.com/questions/20254214/how-can-i-programmatically-determine-if-a-table-exists-within-a-sql-server-ce-da/20339969?noredirect=1#20339969
public static bool TableExists(SqlCeConnection connection, string tableName)
{
    using (var command = new SqlCeCommand())
    {
        command.Connection = connection;
        var sql = string.Format(
            "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = '{0}'", tableName);
        command.CommandText = sql;
        var count = Convert.ToInt32(command.ExecuteScalar());
        return (count > 0);
    }
}

public static void ConditionallyCreateTables()
{
    const string sdfPath = @"\Program Files\hhs\HHS.sdf";
    string dataSource = string.Format("Data Source={0}", sdfPath);

    if (!File.Exists(sdfPath))
    {
        using (var engine = new SqlCeEngine(dataSource))
        {
            engine.CreateDatabase();
        }
    }

    using (var connection = new SqlCeConnection(dataSource))
    {
        connection.Open();
        using (var command = new SqlCeCommand())
        {
            command.Connection = connection;

            // It may be that I'll want to replace "if (!TableExists())" with "if (TableExists())" and then either drop the table in that
            // case and recreate it, or delete its contents
            if (!TableExists(connection, "InventoryItems"))
            {
                command.CommandText = "CREATE TABLE InventoryItems (Id nvarchar(50) NOT NULL, PackSize smallint NOT NULL, Description nvarchar(255), DeptDotSubdept numeric, UnitCost numeric, UnitList numeric, UPCCode nvarchar(50), UPCPackSize smallint, CRVId int);";
                command.ExecuteNonQuery();
            }

            if (!TableExists(connection, "Departments"))
            {
                command.CommandText = "CREATE TABLE Departments (Id int NOT NULL, DeptNum int NOT NULL, DepartmentName nvarchar(255))";
                command.ExecuteNonQuery();
            }

            if (!TableExists(connection, "Subdepartments"))
            {
                command.CommandText = "CREATE TABLE Subdepartments (Id int NOT NULL, DeptId int NOT NULL, SubdeptId int NOT NULL, DepartmentName nvarchar(255))";
                command.ExecuteNonQuery();
            }

            if (!TableExists(connection, "Redemptions"))
            {
                command.CommandText = "CREATE TABLE Redemptions (Id int NOT NULL, RedemptionId nvarchar(50), RedemptionItemId nvarchar(50), RedemptionName nvarchar(255), RedemptionAmount numeric, RedemptionDept nvarchar(50), RedemptionSubdept nvarchar(50))";
                command.ExecuteNonQuery();
            }
        }
    }
}

[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]

С другой стороны, я пришел к выводу (после 20 лет откола в стенах этой соляной шахты профессии, и будучи несчастной жертвой бесчисленных обрушений различной степени тяжести [*]), что программист, вам нужно либо быть безумным (чтобы вас никуда не сводили с толку все это), либо быть абсолютно невосприимчивым к безумию (по той же причине); если вы начнете с любого конца спектра, вы, вероятно, будете в порядке; для тех, кто находится в середине этого континуума (хотя я считаю, что это значительная часть общего населения): остерегайтесь, чтобы ваши чувства не были раздавлены до бесформенной мякоти или сведены в кучу до вопящего (если приглушенного) безумия.

[*****] Да, воистину, при каждом перебежке я обнаруживала, как сжимала кирку в моих истекающих кровью руках.

ОБНОВИТЬ

Я решил ошибку "DEPTNUM", убедившись, что имена столбцов во временной таблице точно совпадают с именами столбцов в таблице SQL Server CE (которые, по мнению Server Explorer, в любом случае не существуют):

var dt = new DataTable();
dt.Columns.Add(new DataColumn("Id", typeof(Int32)));
dt.Columns.Add(new DataColumn("DeptNum", typeof(Int32)));
dt.Columns.Add(new DataColumn("DepartmentName", typeof(string)));

Однако, как указывалось выше, главная загадка (номинальный вопрос поста) остается нерешенной.

ОБНОВЛЕНИЕ 2

Позволить компьютеру вздремнуть и "подумать об этом" ничего не помогло; То же самое верно и сегодня. Код для добавления записей в таблицу SQL Server CE работает нормально; это просто, что Server Explorer, хотя и может нормально подключиться к файлу базы данных портативного устройства (тестовое соединение успешно), не может увидеть файл или делает вид, что не может? КСТАТИ /AWTTW: Я собираюсь как можно скорее обнародовать это (когда-нибудь завтра).

ОБНОВЛЕНИЕ 3

Этот тест:

if (!File.Exists(sdfPath))
{
    using (var engine = new SqlCeEngine(dataSource))
    {
        engine.CreateDatabase();
    }
}

... происходит сбой (условный код не вводится), поэтому мобильное приложение / приложение Windows CE видит файл как существующий во время выполнения.

ОБНОВЛЕНИЕ 4

Я умею читать и писать в таблицы, поэтому приложение может их видеть; Я также могу просмотреть таблицы и их данные на портативном устройстве, перейдя к файлу.SDF; Средство SQL Server CE вызывается при двойном щелчке файла.SDF. Однако в обозревателе серверов в Visual Studio 2008 требуется активировать вызов.

1 ответ

Решение

Ну, во-первых, я скажу, что я никогда и никогда не использовал "Добавить соединение", чтобы попытаться подключиться напрямую к базе данных на устройстве. Может, за десятки с лишним лет разработки для Windows CE я узнал, что практически все, что требует взаимодействия между ПК и устройством вне самого отладчика, чревато опасностью. ActiveSync == "Здесь будут монстры" на карте.

Так я удивлен, что это не работает? Не за что. Я на самом деле более удивлен, что это даже опция в диалоге. Возможно, что версия устройства SQL CE и версия для ПК различаются, и это различие делает его таким, что рабочий стол не может правильно прочитать файл удаления. Или, может быть, это просто неисправное соединение (опять же, смотрите "ActiveSync").

Так как вы продвигаетесь? Легко. Скопируйте базу данных с устройства на ПК, затем откройте копию ПК с помощью Studio. Шутки в сторону. Это именно то, как я это делаю, и это прекрасно работает.

Я думаю, что уже рекомендовал это вам раньше, но это стоит повторить. Избегайте DataTables. Это гигантские боровы памяти, а под CE вы не можете позволить себе боров памяти. По сути, он дублирует всю исходную таблицу в оперативную память для вас. SqlCeDataReader и SqlCeResultSet - ваши друзья.

Другие вопросы по тегам