Расширение Dapper Ms Access System.Data.OleDb.OleDbException

Я только начал использовать Dapper. Дампер работает отлично. В качестве следующего шага, когда я попытался интегрироваться с Dapper Extension. Он генерирует исключение под названием System.Data.OleDb.OleDbException "Additional information: Characters found after end of SQL statement." Это почему? Dapper Extension не поддерживает Ms Access (из-за конечного символа) или проблемы с моим кодом, или я что-то упустил. Мой код ниже

using (var conn = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=myAccessFile.accdb;"))
{
    conn.Open();
    conn.Insert<Person>(new Person { Name = "John Stan", Age = 20 });
}

1 ответ

Согласно статье MSDN,

Некоторые механизмы базы данных, такие как ядро ​​базы данных Microsoft Access Jet, не поддерживают выходные параметры и не могут обрабатывать несколько операторов в одном пакете.

Таким образом, проблема в том, что метод Insert генерирует такой оператор, как

INSERT INTO [Person] ([Person].[PersonName]) VALUES (@PersonName);
SELECT CAST(SCOPE_IDENTITY()  AS BIGINT) AS [Id]

и Access не может справиться с этим.

Читая вокруг, кажется, что есть различные предложения относительно того, как сделать ключ вставки и получения новой записи при работе с Access (эта статья MSDN предлагает второй оператор SELECT), но это не поможет, если вы используя библиотеку DapperExtensions, так как именно это генерирует запрос для вас.

Так что, в принципе, я думаю, что вы правы, считая, что DapperExtensions не будет работать с Access.


Кстати, у меня был кошмар, пытаясь выяснить, какие запросы генерировались. Существуют различные статьи, в которых говорится о взломе реестра для установки значения "JETSHOWPLAN" в значение "ON", но я не смог заставить ни одну из них работать. В конце концов, я создал обернутые соединения с базой данных и классы команд, чтобы запросы могли быть получены при выходе. В случае, если это пригодится кому-либо в будущем, я включу это ниже..

Код инициализации соединения с базой данных должен немного измениться, например.

var connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Database2.mdb;";
using (var conn = new WrappedDbConnection(new OleDbConnection(connectionString)))
{
    conn.Insert<Person>(new Person { PersonName = "Dan" });
}

и следующие два класса должны быть определены -

public class WrappedDbConnection : IDbConnection
{
    private readonly IDbConnection _conn;
    public WrappedDbConnection(IDbConnection connection)
    {
        if (connection == null)
            throw new ArgumentNullException(nameof(connection));

        _conn = connection;
    }

    public string ConnectionString
    {
        get { return _conn.ConnectionString; }
        set { _conn.ConnectionString = value; }
    }

    public int ConnectionTimeout
    {
        get { return _conn.ConnectionTimeout; }
    }

    public string Database
    {
        get { return _conn.Database; }
    }

    public ConnectionState State
    {
        get { return _conn.State; }
    }

    public IDbTransaction BeginTransaction()
    {
        return _conn.BeginTransaction();
    }

    public IDbTransaction BeginTransaction(IsolationLevel il)
    {
        return _conn.BeginTransaction(il);
    }

    public void ChangeDatabase(string databaseName)
    {
        _conn.ChangeDatabase(databaseName);
    }

    public void Close()
    {
        _conn.Close();
    }

    public IDbCommand CreateCommand()
    {
        return new WrappedDbCommand(_conn.CreateCommand());
    }

    public void Dispose()
    {
        _conn.Dispose();
    }

    public void Open()
    {
        _conn.Open();
    }
}

public class WrappedDbCommand : IDbCommand
{
    private readonly IDbCommand _cmd;
    public WrappedDbCommand(IDbCommand command)
    {
        if (command == null)
            throw new ArgumentNullException(nameof(command));

        _cmd = command;
    }

    public string CommandText
    {
        get { return _cmd.CommandText; }
        set { _cmd.CommandText = value; }
    }

    public int CommandTimeout
    {
        get { return _cmd.CommandTimeout; }
        set { _cmd.CommandTimeout = value; }
    }

    public CommandType CommandType
    {
        get { return _cmd.CommandType; }
        set { _cmd.CommandType = value; }
    }

    public IDbConnection Connection
    {
        get { return _cmd.Connection; }
        set { _cmd.Connection = value; }
    }

    public IDataParameterCollection Parameters
    {
        get { return _cmd.Parameters; }
    }

    public IDbTransaction Transaction
    {
        get { return _cmd.Transaction; }
        set { _cmd.Transaction = value; }
    }

    public UpdateRowSource UpdatedRowSource
    {
        get { return _cmd.UpdatedRowSource; }
        set { _cmd.UpdatedRowSource = value; }
    }

    public void Cancel()
    {
        _cmd.Cancel();
    }

    public IDbDataParameter CreateParameter()
    {
        return _cmd.CreateParameter();
    }

    public void Dispose()
    {
        _cmd.Dispose();
    }

    public int ExecuteNonQuery()
    {
        Console.WriteLine($"[ExecuteNonQuery] {_cmd.CommandText}");
        return _cmd.ExecuteNonQuery();
    }

    public IDataReader ExecuteReader()
    {
        Console.WriteLine($"[ExecuteReader] {_cmd.CommandText}");
        return _cmd.ExecuteReader();
    }

    public IDataReader ExecuteReader(CommandBehavior behavior)
    {
        Console.WriteLine($"[ExecuteReader({behavior})] {_cmd.CommandText}");
        return _cmd.ExecuteReader();
    }

    public object ExecuteScalar()
    {
        Console.WriteLine($"[ExecuteScalar] {_cmd.CommandText}");
        return _cmd.ExecuteScalar();
    }

    public void Prepare()
    {
        _cmd.Prepare();
    }
}

Теперь запросы записываются на консоль перед отправкой в ​​базу данных.

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