Refactor to use Dapper async methods and improve readability

Refactored code to utilize Dapper's `ExecuteAsync` and `ExecuteScalarAsync` methods, reducing boilerplate and simplifying SQL command execution. Updated `DeleteDocumentAsync` to a concise expression-bodied member. Replaced manual SQL parameter addition with anonymous objects for better readability and maintainability. Transaction handling remains unchanged to ensure consistent database operations.
This commit is contained in:
Marco Minerva
2024-10-16 15:06:34 +02:00
parent 31b2a79b9f
commit 1a5542f1d2
@@ -33,41 +33,25 @@ public class VectorSearchService(SqlConnection sqlConnection, ITextEmbeddingGene
await DeleteDocumentAsync(documentId.Value, transaction); await DeleteDocumentAsync(documentId.Value, transaction);
} }
await using var command = sqlConnection.CreateCommand(); documentId = await sqlConnection.ExecuteScalarAsync<Guid>($"""
command.Transaction = (SqlTransaction)transaction;
command.CommandText = """
INSERT INTO Documents (Id, [Name], CreationDate) INSERT INTO Documents (Id, [Name], CreationDate)
OUTPUT INSERTED.Id OUTPUT INSERTED.Id
VALUES (@Id, @Name, @CreationDate); VALUES (@Id, @Name, @CreationDate);
"""; """, new { Id = documentId.GetValueOrDefault(Guid.NewGuid()), Name = name, CreationDate = timeProvider.GetUtcNow() },
transaction);
command.Parameters.AddWithValue("@Id", documentId.GetValueOrDefault(Guid.NewGuid()));
command.Parameters.AddWithValue("@Name", name);
command.Parameters.AddWithValue("@CreationDate", timeProvider.GetUtcNow());
var insertedId = await command.ExecuteScalarAsync();
documentId = (Guid)insertedId!;
// Split the content into chunks and generate the embeddings for each one. // Split the content into chunks and generate the embeddings for each one.
var paragraphs = TextChunker.SplitPlainTextParagraphs(TextChunker.SplitPlainTextLines(content, appSettings.MaxTokensPerLine), appSettings.MaxTokensPerParagraph, appSettings.OverlapTokens); var paragraphs = TextChunker.SplitPlainTextParagraphs(TextChunker.SplitPlainTextLines(content, appSettings.MaxTokensPerLine), appSettings.MaxTokensPerParagraph, appSettings.OverlapTokens);
var embeddings = await textEmbeddingGenerationService.GenerateEmbeddingsAsync(paragraphs); var embeddings = await textEmbeddingGenerationService.GenerateEmbeddingsAsync(paragraphs);
// Save the document chunks and the corresponding embedding in the database.
foreach (var (paragraph, index) in paragraphs.WithIndex()) foreach (var (paragraph, index) in paragraphs.WithIndex())
{ {
command.Parameters.Clear(); await sqlConnection.ExecuteAsync($"""
command.CommandText = $"""
INSERT INTO DocumentChunks (DocumentId, [Index], Content, Embedding) INSERT INTO DocumentChunks (DocumentId, [Index], Content, Embedding)
VALUES (@DocumentId, @Index, @Content, CAST(@Embedding AS VECTOR({embeddings[index].Length}))); VALUES (@DocumentId, @Index, @Content, CAST(@Embedding AS VECTOR({embeddings[index].Length})));
"""; """, new { DocumentId = documentId, Index = index, Content = paragraph, Embedding = JsonSerializer.Serialize(embeddings[index]) },
transaction);
command.Parameters.AddWithValue("@DocumentId", documentId);
command.Parameters.AddWithValue("@Index", index);
command.Parameters.AddWithValue("@Content", paragraph);
command.Parameters.AddWithValue("@Embedding", JsonSerializer.Serialize(embeddings[index]));
await command.ExecuteNonQueryAsync();
} }
await transaction.CommitAsync(); await transaction.CommitAsync();
@@ -109,21 +93,8 @@ public class VectorSearchService(SqlConnection sqlConnection, ITextEmbeddingGene
return documentChunk; return documentChunk;
} }
public async Task DeleteDocumentAsync(Guid documentId, DbTransaction? transaction = null) public Task DeleteDocumentAsync(Guid documentId, DbTransaction? transaction = null)
{ => sqlConnection.ExecuteAsync("DELETE FROM Documents WHERE Id = @DocumentId", new { DocumentId = documentId }, transaction);
if (sqlConnection.State == ConnectionState.Closed)
{
await sqlConnection.OpenAsync();
}
await using var command = sqlConnection.CreateCommand();
command.Transaction = transaction as SqlTransaction;
command.CommandText = "DELETE FROM Documents WHERE Id = @DocumentId";
command.Parameters.AddWithValue("@DocumentId", documentId);
await command.ExecuteNonQueryAsync();
}
public async Task<Response> AskQuestionAsync(Question question, bool reformulate = true) public async Task<Response> AskQuestionAsync(Question question, bool reformulate = true)
{ {