2

I did some digging into this, but I don't quite understand it. I have a Microsoft.Extensions.Logging.EventId on an object and I've used Dapper to preserve the EventId in my database. I used two columns: EventId (int) and EventName (varchar(…)). However, I can't quite figure out how to populate the one property object (EventId) from the two database columns.

I tried manipulating my SQL . .

SELECT <snip>…[EventId] AS [EventId.Id],[EventName] AS [EventId.Name] . . .

but that worked about as you might expect.

So, here's my xunit test:

[Fact]
public async Task EventName_Retrievable()
{
    logger.Log(logLevel: LogLevel.Critical,
        eventId: new EventId(10, "find me"),
        exception: null,
        state: "yes please",
        formatter: (s, e) =>
        {
            return e?.Message ?? s;
        });

    var criteria = new LogQueryCriteria
    {
        MessageContains = "yes please"
    };
    var service = new LogQueryService(_fixture.ConnectionString, _factory, _performanceAgent);

    var logs = await service.FindLogsAsync(criteria);

    Assert.NotEmpty(logs);

    Assert.Equal("find me", logs.Last().EventId.Name);
}

which proves that this function doesn't work:

    public async Task<IEnumerable<ILogItemOutbound>> FindLogsAsync(LogQueryCriteria criteria)
    {
        var pe = _performanceAgent?.Start($"{nameof(LogQueryService)}.{nameof(FindLogsAsync)}", PerformanceTrackingLevel.Low);

        if (criteria == null) { criteria = new LogQueryCriteria(); }

        IEnumerable<ILogItemOutbound> results = null;
        var sql = $@"
{Constants.SELECT_LOGS}{ConstructWhereClause(criteria)} {ConstructOrderByClause(criteria)}
OFFSET {criteria.OffsetValue} ROWS FETCH NEXT {criteria.NumberPerPage} ROWS ONLY;";

        using (var connection = new SqlConnection(_connectionString))
        {
            connection.Open();
            results = await connection.QueryAsync<LogItemOutbound, EventId, LogItemOutbound>(sql: sql, commandType: System.Data.CommandType.Text,
                map: (logItem, eventId) =>
                {
                    logItem.EventId = eventId;
                    return logItem;
                }
            , splitOn: "EventId");
            _performanceAgent?.Finish(pe);
        }

        return results ?? new List<ILogItemOutbound>();
    }

You can see that I attempted to use the map function sort of like this person did: https://taylorhutchison.github.io/2016/03/23/dapper-orm-complex-queries.html, but the Name always turns up NULL, regardless of my approach.

Anyone see where I'm going wrong?

If relevant, here is my SQL:

    internal const string SELECT_LOGS = @"
SET NOCOUNT ON;
SET DEADLOCK_PRIORITY NORMAL;

SELECT [GlobalId]
,[UtcTimestamp]
,[Message]
,[LogLevel]
,[LogLevelName]
,[Source]
,[UserIdentity]
,[SessionId]
,[EventId]
,[EventName]
FROM [dbo].[Logs]";

Help is always appreciated.

V

1 Answer 1

1

EventName will not map to Event.Name

Change your SQL to

 internal const string SELECT_LOGS = @"
SET NOCOUNT ON;
SET DEADLOCK_PRIORITY NORMAL;

SELECT [GlobalId]
,[UtcTimestamp]
,[Message]
,[LogLevel]
,[LogLevelName]
,[Source]
,[UserIdentity]
,[SessionId]
,[EventId] as Id
,[EventName] as Name
FROM [dbo].[Logs]";

and your spliton: "Id"

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.