mirror of
https://github.com/marcominerva/SqlDatabaseVectorSearch.git
synced 2026-06-20 12:23:10 +00:00
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:
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user