简体   繁体   中英

Entity Framework Core - Execute raw sql - Same code for SQL/SQLite

I'm currently using two different Connections types, (SQLConnection for normal use and SqliteConnection for integration testing), when inserting new exceptions in my LogService.

Because I don't have access to the database context class I'll have to use raw sql to insert new entities, (I only have the database connectionstring).

When running integration tests I have to use SQLite in memory database because of the entity relations, (SQL does not support this in memory).

protected async Task InsertException(DateTime utcNow, LogLevel logLevel, EventId eventId, string state, Exception exception, CategoryAppSettings categoryAppSettings, string caller, string ipAddress, int? userId, int? organisationId, string requestId)
{
    string stackTrace = exception?.StackTrace;

    string query =
        "INSERT INTO [Exception] " +
        "(" +
            "[Created]" +
            ",[EventId]" +
            ",[IpAddress]" +
            ",[LogLevel]" +
            ",[Message]" +
            ",[Source]" +
            ",[StackTrace]" +
            ",[State]" +
            ",[UserId]" +
            ",[OrganisationId]" +
            ",[RequestId]" +
        ")" +
        "VALUES" +
        "(" +
            "@Created" +
            ",@EventId" +
            ",@IpAddress" +
            ",@LogLevel" +
            ",@Message" +
            ",@Source" +
            ",@StackTrace" +
            ",@State" +
            ",@UserId" +
            ",@OrganisationId" +
            ",@RequestId" +
        ")";

    Dictionary<string, object> parameters = new Dictionary<string, object>
    {
        { "@Created", utcNow },
        { "@EventId", eventId.ToString() ?? (object)DBNull.Value },
        { "@IpAddress", ipAddress ?? (object)DBNull.Value },
        { "@LogLevel", logLevel.ToString() ?? (object)DBNull.Value },
        { "@Message", exception?.Message ?? (object)DBNull.Value },
        { "@Source", caller ?? (object)DBNull.Value },
        { "@StackTrace", stackTrace?.Trim() ?? (object)DBNull.Value },
        { "@State", state ?? (object)DBNull.Value },
        { "@UserId", userId ?? (object)DBNull.Value },
        { "@OrganisationId", organisationId ?? (object)DBNull.Value },
        { "@RequestId", requestId ?? (object)DBNull.Value },
    };
    try
    {
        if (_hostingEnvironment.EnvironmentName == "Test")
        {
            using (SqliteConnection sqlConnection = new SqliteConnection($"Data Source={_logAppSettings.ConnectionStrings.Database};Mode=Memory;Cache=Shared;"))
            {
                using (SqliteCommand sqlCommand = new SqliteCommand(query, sqlConnection))
                {
                    foreach (var parameter in parameters)
                    {
                        sqlCommand.Parameters.Add(new SqliteParameter(parameter.Key, parameter.Value));
                    }

                    sqlConnection.Open();

                    await sqlCommand.ExecuteNonQueryAsync();
                }
            }
        }
        else
        {
            using (SqlConnection sqlConnection = new SqlConnection(_logAppSettings.ConnectionStrings.Database))
            {
                using (SqlCommand sqlCommand = new SqlCommand(query, sqlConnection))
                {
                    foreach (var parameter in parameters)
                    {
                        sqlCommand.Parameters.Add(new SqlParameter(parameter.Key, parameter.Value));
                    }

                    sqlConnection.Open();

                    await sqlCommand.ExecuteNonQueryAsync();
                }
            }
        }
    }
    catch (Exception ex)
    {
        ExceptionModel exceptionModel = new ExceptionModel()
        {
            StackTrace = ex?.StackTrace,
            Message = ex?.Message,
            InnerException = ex?.InnerException.ToString()
        };

        LogModel log = new LogModel()
        {
            Created = $"{utcNow:yyyy-MM-dd HH:mm}",
            LogLevel = LogLevel.Error.ToString(),
            EventId = LogEvents.Log,
            Source = ex.Source,
            IpAddress = ipAddress,
            UserId = userId,
            OrganisationId = organisationId,
            State = "An unexpected error occured while trying to insert new exception.",
            Exception = exceptionModel,
            RequestId = requestId
        };

        InsertLog(utcNow, log, categoryAppSettings);
    }
}

As you can see I'm using two different database types, two different connection types. I really don't like it when you have to customize your code just to make the test greens!

Is it possible to have one connection type for both databases?

I've looked at "Entity SQL" but I don't think it's supported in Entity Framework Core and it's abit legacy-ish..

It's maybe not exactly, what you want , but you can avoid doubling code by using DbConnection instead of SQLConnection. You can define the DbConnectionType anywhere else like:

Type connectionType = _hostingEnvironment.EnvironmentName == "Test" ? typeof(SqliteConnection) : typeof(SqlConnection);

// If you switch the Connection String outside too, it should work:
string connectionString = _hostingEnvironment.EnvironmentName == "Test" ? $"Data Source={_logAppSettings.ConnectionStrings.Database};Mode=Memory;Cache=Shared;" : _logAppSettings.ConnectionStrings.Database;


        using (DbConnection sqlConnection = Activator.CreateInstance(connectionType, new object[] {connectionString}) as DbConnection)
        {
            using (DbCommand sqlCommand = sqlConnection.CreateCommand())
            {
                sqlCommand.CommandText = query;
                foreach (var parameter in parameters)
                {
                   DbParameter param = sqlCommand.CreateParameter();
                   param.ParameterName= parameter.Key;
                   param.Value=parameter.Value;
                   sqlCommand.Parameters.Add(param );
                }

                sqlConnection.Open();

                await sqlCommand.ExecuteNonQueryAsync();


        }
    }
}

I hope this helps you!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM