Fix Dapper Provider (#4998)

* Update Dapper for better support and pagination

The update includes a significant enhancement to the Dapper module. Improvements were made to support SQL Server and enhanced SQL query pagination. Additionally, table column size was increased for various fields to handle more extensive data. Minor refactoring was also done to improve code readability.

* Toggle SQL Server usage in Elsa Server

The previous setting had SQL Server usage in Elsa server enabled by default. This commit changes the useSqlServer constant in Elsa.Server.Web to false, effectively switching SQL Server off unless manually activated.
This commit is contained in:
Sipke Schoorstra 2024-02-25 20:36:31 +01:00 committed by GitHub
parent e48c5e2075
commit 330dc1a0d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 201 additions and 82 deletions

View file

@ -54,7 +54,13 @@ services
if (useDapper)
elsa.UseDapper(dapper =>
{
dapper.UseMigrations();
dapper.UseMigrations(feature =>
{
if (useSqlServer)
feature.UseSqlServer();
else
feature.UseSqlite();
});
dapper.DbConnectionProvider = sp =>
{
if (useSqlServer)
@ -108,8 +114,8 @@ services
else
ef.UseSqlite(sqliteConnectionString);
});
if(useZipCompression)
if (useZipCompression)
management.SetCompressionAlgorithm(nameof(Zstd));
})
.UseWorkflowRuntime(runtime =>
@ -138,10 +144,11 @@ services
});
}
if(useMassTransit)
if (useMassTransit)
{
runtime.UseMassTransitDispatcher();
}
runtime.WorkflowInboxCleanupOptions = options => configuration.GetSection("Runtime:WorkflowInboxCleanup").Bind(options);
runtime.WorkflowDispatcherOptions = options => configuration.GetSection("Runtime:WorkflowDispatcher").Bind(options);
})
@ -187,19 +194,29 @@ services
.UseEmail(email => email.ConfigureOptions = options => configuration.GetSection("Smtp").Bind(options))
.UseAlterations(alterations =>
{
alterations.UseEntityFrameworkCore(ef =>
if (useMongoDb)
{
if (useSqlServer)
ef.UseSqlServer(sqlServerConnectionString);
else
ef.UseSqlite(sqliteConnectionString);
});
// TODO: alterations.UseMongoDb();
}
else if (useDapper)
{
// TODO: alterations.UseDapper();
}
else
{
alterations.UseEntityFrameworkCore(ef =>
{
if (useSqlServer)
ef.UseSqlServer(sqlServerConnectionString);
else
ef.UseSqlite(sqliteConnectionString);
});
}
if (useMassTransit)
{
alterations.UseMassTransitDispatcher();
}
})
.UseWorkflowContexts();

View file

@ -1,5 +1,6 @@
using FluentMigrator;
using JetBrains.Annotations;
using static System.Int32;
namespace Elsa.Dapper.Migrations.Identity;
@ -17,13 +18,13 @@ public class Initial : Migration
.WithColumn("Name").AsString().NotNullable()
.WithColumn("HashedPassword").AsString().NotNullable()
.WithColumn("HashedPasswordSalt").AsString().NotNullable()
.WithColumn("Roles").AsString().NotNullable();
.WithColumn("Roles").AsString(MaxValue).NotNullable();
Create
.Table("Roles")
.WithColumn("Id").AsString().PrimaryKey()
.WithColumn("Name").AsString().NotNullable()
.WithColumn("Permissions").AsString().NotNullable();
.WithColumn("Permissions").AsString(MaxValue).NotNullable();
Create
.Table("Applications")
@ -34,7 +35,7 @@ public class Initial : Migration
.WithColumn("Name").AsString().NotNullable()
.WithColumn("HashedApiKey").AsString().NotNullable()
.WithColumn("HashedApiKeySalt").AsString().NotNullable()
.WithColumn("Roles").AsString().NotNullable();
.WithColumn("Roles").AsString(MaxValue).NotNullable();
}
/// <inheritdoc />

View file

@ -1,5 +1,6 @@
using FluentMigrator;
using JetBrains.Annotations;
using static System.Int32;
namespace Elsa.Dapper.Migrations.Management;
@ -18,14 +19,14 @@ public class Initial : Migration
.WithColumn("DefinitionId").AsString().NotNullable()
.WithColumn("Name").AsString().Nullable()
.WithColumn("ToolVersion").AsString().Nullable()
.WithColumn("Description").AsString().Nullable()
.WithColumn("Description").AsString(MaxValue).Nullable()
.WithColumn("ProviderName").AsString().Nullable()
.WithColumn("MaterializerName").AsString().NotNullable()
.WithColumn("MaterializerContext").AsString().Nullable()
.WithColumn("Props").AsString().NotNullable()
.WithColumn("MaterializerContext").AsString(MaxValue).Nullable()
.WithColumn("Props").AsString(MaxValue).NotNullable()
.WithColumn("UsableAsActivity").AsBoolean().Nullable()
.WithColumn("StringData").AsString().Nullable()
.WithColumn("BinaryData").AsBinary().Nullable()
.WithColumn("StringData").AsString(MaxValue).Nullable()
.WithColumn("BinaryData").AsBinary(MaxValue).Nullable()
.WithColumn("CreatedAt").AsDateTimeOffset().NotNullable()
.WithColumn("Version").AsInt32().NotNullable()
.WithColumn("IsLatest").AsBoolean().NotNullable()
@ -40,14 +41,14 @@ public class Initial : Migration
.WithColumn("DefinitionId").AsString().NotNullable()
.WithColumn("Name").AsString().Nullable()
.WithColumn("ToolVersion").AsString().Nullable()
.WithColumn("Description").AsString().Nullable()
.WithColumn("Description").AsString(MaxValue).Nullable()
.WithColumn("ProviderName").AsString().Nullable()
.WithColumn("MaterializerName").AsString().NotNullable()
.WithColumn("MaterializerContext").AsString().Nullable()
.WithColumn("Props").AsString().NotNullable()
.WithColumn("Props").AsString(MaxValue).NotNullable()
.WithColumn("UsableAsActivity").AsBoolean().Nullable()
.WithColumn("StringData").AsString().Nullable()
.WithColumn("BinaryData").AsBinary().Nullable()
.WithColumn("StringData").AsString(MaxValue).Nullable()
.WithColumn("BinaryData").AsBinary(MaxValue).Nullable()
.WithColumn("CreatedAt").AsDateTime2().NotNullable()
.WithColumn("Version").AsInt32().NotNullable()
.WithColumn("IsLatest").AsBoolean().NotNullable()
@ -61,7 +62,7 @@ public class Initial : Migration
.WithColumn("DefinitionId").AsString().NotNullable()
.WithColumn("DefinitionVersionId").AsString().NotNullable()
.WithColumn("Version").AsInt32().NotNullable()
.WithColumn("WorkflowState").AsString().NotNullable()
.WithColumn("WorkflowState").AsString(MaxValue).NotNullable()
.WithColumn("Status").AsString().NotNullable()
.WithColumn("SubStatus").AsString().NotNullable()
.WithColumn("CorrelationId").AsString().Nullable()
@ -78,7 +79,7 @@ public class Initial : Migration
.WithColumn("DefinitionId").AsString().NotNullable()
.WithColumn("DefinitionVersionId").AsString().NotNullable()
.WithColumn("Version").AsInt32().NotNullable()
.WithColumn("WorkflowState").AsString().NotNullable()
.WithColumn("WorkflowState").AsString(MaxValue).NotNullable()
.WithColumn("Status").AsString().NotNullable()
.WithColumn("SubStatus").AsString().NotNullable()
.WithColumn("CorrelationId").AsString().Nullable()

View file

@ -1,5 +1,6 @@
using FluentMigrator;
using JetBrains.Annotations;
using static System.Int32;
namespace Elsa.Dapper.Migrations.Runtime;
@ -8,6 +9,7 @@ namespace Elsa.Dapper.Migrations.Runtime;
[PublicAPI]
public class Initial : Migration
{
private const int MaxNodeIdColumnLength = 2048;
/// <inheritdoc />
public override void Up()
{
@ -19,7 +21,7 @@ public class Initial : Migration
.WithColumn("Name").AsString().NotNullable().Indexed()
.WithColumn("ActivityId").AsString().NotNullable().Indexed()
.WithColumn("Hash").AsString().Nullable().Indexed()
.WithColumn("SerializedPayload").AsString().Nullable();
.WithColumn("SerializedPayload").AsString(MaxValue).Nullable();
IfDatabase("SqlServer", "Oracle", "MySql", "Postgres")
.Create
@ -30,8 +32,8 @@ public class Initial : Migration
.WithColumn("CorrelationId").AsString().Nullable().Indexed()
.WithColumn("ActivityInstanceId").AsString().NotNullable().Indexed()
.WithColumn("Hash").AsString().Nullable().Indexed()
.WithColumn("SerializedPayload").AsString().Nullable()
.WithColumn("SerializedMetadata").AsString().Nullable()
.WithColumn("SerializedPayload").AsString(MaxValue).Nullable()
.WithColumn("SerializedMetadata").AsString(MaxValue).Nullable()
.WithColumn("CreatedAt").AsDateTimeOffset().NotNullable().Indexed();
IfDatabase("Sqlite")
@ -43,8 +45,8 @@ public class Initial : Migration
.WithColumn("CorrelationId").AsString().Nullable().Indexed()
.WithColumn("ActivityInstanceId").AsString().NotNullable().Indexed()
.WithColumn("Hash").AsString().Nullable().Indexed()
.WithColumn("SerializedPayload").AsString().Nullable()
.WithColumn("SerializedMetadata").AsString().Nullable()
.WithColumn("SerializedPayload").AsString(MaxValue).Nullable()
.WithColumn("SerializedMetadata").AsString(MaxValue).Nullable()
.WithColumn("CreatedAt").AsDateTime2().NotNullable().Indexed();
IfDatabase("SqlServer", "Oracle", "MySql", "Postgres")
@ -61,13 +63,13 @@ public class Initial : Migration
.WithColumn("ActivityType").AsString().NotNullable().Indexed()
.WithColumn("ActivityTypeVersion").AsInt32().NotNullable().Indexed()
.WithColumn("ActivityName").AsString().Nullable().Indexed()
.WithColumn("ActivityNodeId").AsString().NotNullable().Indexed()
.WithColumn("ActivityNodeId").AsString(MaxNodeIdColumnLength).NotNullable().Indexed()
.WithColumn("EventName").AsString().Nullable().Indexed()
.WithColumn("Message").AsString().Nullable()
.WithColumn("Message").AsString(MaxValue).Nullable()
.WithColumn("Source").AsString().Nullable()
.WithColumn("SerializedActivityState").AsString().Nullable()
.WithColumn("SerializedPayload").AsString().Nullable()
.WithColumn("SerializedException").AsString().Nullable()
.WithColumn("SerializedActivityState").AsString(MaxValue).Nullable()
.WithColumn("SerializedPayload").AsString(MaxValue).Nullable()
.WithColumn("SerializedException").AsString(MaxValue).Nullable()
.WithColumn("Timestamp").AsDateTimeOffset().NotNullable().Indexed()
.WithColumn("Sequence").AsInt64().NotNullable().Indexed()
;
@ -86,14 +88,14 @@ public class Initial : Migration
.WithColumn("ActivityType").AsString().NotNullable().Indexed()
.WithColumn("ActivityTypeVersion").AsInt32().NotNullable().Indexed()
.WithColumn("ActivityName").AsString().Nullable().Indexed()
.WithColumn("ActivityNodeId").AsString().NotNullable().Indexed()
.WithColumn("ActivityNodeId").AsString(MaxNodeIdColumnLength).NotNullable().Indexed()
.WithColumn("EventName").AsString().Nullable().Indexed()
.WithColumn("Message").AsString().Nullable()
.WithColumn("Message").AsString(MaxValue).Nullable()
.WithColumn("Source").AsString().Nullable()
.WithColumn("SerializedActivityState").AsString().Nullable()
.WithColumn("SerializedPayload").AsString().Nullable()
.WithColumn("SerializedOutputs").AsString().Nullable()
.WithColumn("SerializedException").AsString().Nullable()
.WithColumn("SerializedActivityState").AsString(MaxValue).Nullable()
.WithColumn("SerializedPayload").AsString(MaxValue).Nullable()
.WithColumn("SerializedOutputs").AsString(MaxValue).Nullable()
.WithColumn("SerializedException").AsString(MaxValue).Nullable()
.WithColumn("Timestamp").AsDateTime2().NotNullable().Indexed()
.WithColumn("Sequence").AsInt64().NotNullable().Indexed()
;
@ -104,14 +106,14 @@ public class Initial : Migration
.WithColumn("Id").AsString().PrimaryKey()
.WithColumn("WorkflowInstanceId").AsString().NotNullable().Indexed()
.WithColumn("ActivityId").AsString().NotNullable().Indexed()
.WithColumn("ActivityNodeId").AsString().NotNullable().Indexed()
.WithColumn("ActivityNodeId").AsString(MaxNodeIdColumnLength).NotNullable().Indexed()
.WithColumn("ActivityType").AsString().NotNullable().Indexed()
.WithColumn("ActivityTypeVersion").AsInt32().NotNullable().Indexed()
.WithColumn("ActivityName").AsString().Nullable().Indexed()
.WithColumn("SerializedActivityState").AsString().Nullable()
.WithColumn("SerializedPayload").AsString().Nullable()
.WithColumn("SerializedOutputs").AsString().Nullable()
.WithColumn("SerializedException").AsString().Nullable()
.WithColumn("SerializedActivityState").AsString(MaxValue).Nullable()
.WithColumn("SerializedPayload").AsString(MaxValue).Nullable()
.WithColumn("SerializedOutputs").AsString(MaxValue).Nullable()
.WithColumn("SerializedException").AsString(MaxValue).Nullable()
.WithColumn("StartedAt").AsDateTimeOffset().NotNullable().Indexed()
.WithColumn("CompletedAt").AsDateTimeOffset().Nullable().Indexed()
.WithColumn("HasBookmarks").AsBoolean().NotNullable().Indexed()
@ -124,14 +126,14 @@ public class Initial : Migration
.WithColumn("Id").AsString().PrimaryKey()
.WithColumn("WorkflowInstanceId").AsString().NotNullable().Indexed()
.WithColumn("ActivityId").AsString().NotNullable().Indexed()
.WithColumn("ActivityNodeId").AsString().NotNullable().Indexed()
.WithColumn("ActivityNodeId").AsString(MaxNodeIdColumnLength).NotNullable().Indexed()
.WithColumn("ActivityType").AsString().NotNullable().Indexed()
.WithColumn("ActivityTypeVersion").AsInt32().NotNullable().Indexed()
.WithColumn("ActivityName").AsString().Nullable().Indexed()
.WithColumn("SerializedActivityState").AsString().Nullable()
.WithColumn("SerializedPayload").AsString().Nullable()
.WithColumn("SerializedOutputs").AsString().Nullable()
.WithColumn("SerializedException").AsString().Nullable()
.WithColumn("SerializedActivityState").AsString(MaxValue).Nullable()
.WithColumn("SerializedPayload").AsString(MaxValue).Nullable()
.WithColumn("SerializedOutputs").AsString(MaxValue).Nullable()
.WithColumn("SerializedException").AsString(MaxValue).Nullable()
.WithColumn("StartedAt").AsDateTime2().NotNullable().Indexed()
.WithColumn("CompletedAt").AsDateTime2().Nullable().Indexed()
.WithColumn("HasBookmarks").AsBoolean().NotNullable().Indexed()
@ -147,8 +149,8 @@ public class Initial : Migration
.WithColumn("ActivityInstanceId").AsString().Nullable().Indexed()
.WithColumn("CorrelationId").AsString().Nullable().Indexed()
.WithColumn("Hash").AsString().NotNullable().Indexed()
.WithColumn("SerializedBookmarkPayload").AsString()
.WithColumn("SerializedInput").AsString().Nullable()
.WithColumn("SerializedBookmarkPayload").AsString(MaxValue)
.WithColumn("SerializedInput").AsString(MaxValue).Nullable()
.WithColumn("CreatedAt").AsDateTimeOffset().Indexed()
.WithColumn("ExpiresAt").AsDateTimeOffset().Indexed()
;
@ -162,8 +164,8 @@ public class Initial : Migration
.WithColumn("ActivityInstanceId").AsString().Nullable().Indexed()
.WithColumn("CorrelationId").AsString().Nullable().Indexed()
.WithColumn("Hash").AsString().NotNullable().Indexed()
.WithColumn("SerializedBookmarkPayload").AsString()
.WithColumn("SerializedInput").AsString().Nullable()
.WithColumn("SerializedBookmarkPayload").AsString(MaxValue)
.WithColumn("SerializedInput").AsString(MaxValue).Nullable()
.WithColumn("CreatedAt").AsDateTime2().Indexed()
.WithColumn("ExpiresAt").AsDateTime2().Indexed()
;

View file

@ -1,11 +1,14 @@
using System.Diagnostics.CodeAnalysis;
using FluentMigrator;
using JetBrains.Annotations;
using static System.Int32;
namespace Elsa.Dapper.Migrations.Runtime;
/// <inheritdoc />
[Migration(20002, "Elsa:Runtime:AddKeyValueStore")]
[PublicAPI]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class V3_1 : Migration
{
/// <inheritdoc />
@ -14,7 +17,7 @@ public class V3_1 : Migration
Create
.Table("KeyValuePairs")
.WithColumn("Key").AsString().PrimaryKey()
.WithColumn("Value").AsString().NotNullable();
.WithColumn("Value").AsString(MaxValue).NotNullable();
}
/// <inheritdoc />

View file

@ -1,4 +1,6 @@
using System.Text;
using Elsa.Common.Entities;
using Elsa.Common.Models;
using Elsa.Dapper.Contracts;
namespace Elsa.Dapper.Abstractions;
@ -53,10 +55,25 @@ public abstract class SqlDialectBase : ISqlDialect
}
/// <inheritdoc />
public virtual string Skip(int count) => $"offset {count}";
public virtual string Skip(int count) => $"offset {count} rows";
/// <inheritdoc />
public virtual string Take(int count) => $"limit {count}";
public virtual string Take(int count) => $"fetch next {count} rows only";
/// <inheritdoc />
public virtual string Page(PageArgs pageArgs)
{
var sb = new StringBuilder();
// Attention: the order is important here for SQL Server (OFFSET before FETCH NEXT).
if (pageArgs.Offset != null)
sb.AppendLine(Skip(pageArgs.Offset.Value));
if (pageArgs.Limit != null)
sb.AppendLine(Take(pageArgs.Limit.Value));
return sb.ToString();
}
/// <inheritdoc />
public string Insert(string table, string[] fields, Func<string, string>? getParamName = default)
@ -75,6 +92,15 @@ public abstract class SqlDialectBase : ISqlDialect
var fieldList = string.Join(", ", fields);
var fieldParamNames = fields.Select(x => $"@{getParamName(x)}");
var fieldParamList = string.Join(", ", fieldParamNames);
return $"INSERT OR REPLACE INTO {table} ({primaryKeyField}, {fieldList}) VALUES (@{getParamName(primaryKeyField)}, {fieldParamList});";
return @$"
MERGE INTO {table} WITH (HOLDLOCK) AS Target
USING (VALUES (@{getParamName(primaryKeyField)}, {fieldParamList}))
AS Source ({primaryKeyField}, {fieldList})
ON Target.{primaryKeyField} = Source.{primaryKeyField}
WHEN MATCHED THEN
UPDATE SET {string.Join(", ", fields.Select(x => $"{x} = Source.{x}"))}
WHEN NOT MATCHED THEN
INSERT ({primaryKeyField}, {fieldList})
VALUES (Source.{primaryKeyField}, {string.Join(", ", fields.Select(x => $"Source.{x}"))});";
}
}

View file

@ -1,4 +1,5 @@
using Elsa.Common.Entities;
using Elsa.Common.Models;
namespace Elsa.Dapper.Contracts;
@ -96,6 +97,13 @@ public interface ISqlDialect
/// <param name="count">The number of records to take.</param>
string Take(int count);
/// <summary>
/// Adds pagination to a SQL query.
/// </summary>
/// <param name="pageArgs">The pagination arguments.</param>
/// <returns>The modified SQL query with pagination.</returns>
string Page(PageArgs pageArgs);
/// <summary>
/// Builds an INSERT query.
/// </summary>

View file

@ -8,8 +8,8 @@ namespace Elsa.Dapper.Dialects;
public class SqlServerDialect : SqlDialectBase
{
/// <inheritdoc />
public override string Skip(int count) => $"OFFSET {count} ROWS";
public override string Skip(int count) => $"Offset {count} Rows";
/// <inheritdoc />
public override string Take(int count) => $"FETCH NEXT {count} ROWS ONLY";
public override string Take(int count) => $"fetch next {count} rows only";
}

View file

@ -1,3 +1,5 @@
using System.Text;
using Elsa.Common.Models;
using Elsa.Dapper.Abstractions;
namespace Elsa.Dapper.Dialects;
@ -7,4 +9,33 @@ namespace Elsa.Dapper.Dialects;
/// </summary>
public class SqliteDialect : SqlDialectBase
{
/// <inheritdoc />
public override string Skip(int count) => $"offset {count}";
/// <inheritdoc />
public override string Take(int count) => $"limit {count}";
/// <inheritdoc />
public override string Page(PageArgs pageArgs)
{
var sb = new StringBuilder();
// Attention: the order is important here for SQLite (LIMIT must come before OFFSET).
if (pageArgs.Limit != null)
sb.AppendLine(Take(pageArgs.Limit.Value));
if (pageArgs.Offset != null)
sb.AppendLine(Skip(pageArgs.Offset.Value));
return sb.ToString();
}
public override string Upsert(string table, string primaryKeyField, string[] fields, Func<string, string>? getParamName = default)
{
getParamName ??= x => x;
var fieldList = string.Join(", ", fields);
var fieldParamNames = fields.Select(x => $"@{getParamName(x)}");
var fieldParamList = string.Join(", ", fieldParamNames);
return $"INSERT OR REPLACE INTO {table} ({primaryKeyField}, {fieldList}) VALUES (@{getParamName(primaryKeyField)}, {fieldParamList});";
}
}

View file

@ -1,3 +1,4 @@
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using Elsa.Common.Entities;
@ -75,11 +76,12 @@ public static class ParameterizedQueryBuilderExtensions
/// </summary>
/// <param name="query">The query.</param>
/// <param name="table">The table.</param>
/// <param name="primaryKey">The primary key.</param>
/// <param name="innerQuery">The inner query.</param>
public static ParameterizedQuery Delete(this ParameterizedQuery query, string table, ParameterizedQuery innerQuery)
public static ParameterizedQuery Delete(this ParameterizedQuery query, string table, string primaryKey, ParameterizedQuery innerQuery)
{
query.Sql.AppendLine(query.Dialect.Delete(table));
query.Sql.AppendLine("and rowid in (");
query.Sql.AppendLine($"and {primaryKey} in (");
query.Sql.AppendLine(innerQuery.Sql.ToString());
query.Sql.AppendLine(")");
return query;
@ -324,13 +326,7 @@ public static class ParameterizedQueryBuilderExtensions
/// <param name="pageArgs">The page arguments.</param>
public static ParameterizedQuery Page(this ParameterizedQuery query, PageArgs pageArgs)
{
// Attention: the order is important here for SQLite (LIMIT must come before OFFSET).
if (pageArgs.Limit != null)
query.Take(pageArgs.Limit.Value);
if (pageArgs.Offset != null)
query.Skip(pageArgs.Offset.Value);
query.Sql.AppendLine(query.Dialect.Page(pageArgs));
return query;
}
@ -350,16 +346,20 @@ public static class ParameterizedQueryBuilderExtensions
.ToArray();
getParameterName ??= x => x;
query.Sql.AppendLine(query.Dialect.Upsert(table, primaryKeyField, fields, getParameterName));
var primaryKeyValue = record.GetType().GetProperty(primaryKeyField)?.GetValue(record);
query.Parameters.Add($"@{getParameterName(primaryKeyField)}", primaryKeyValue);
var recordType = record.GetType();
foreach (var field in fields)
{
var value = record.GetType().GetProperty(field)?.GetValue(record);
query.Parameters.Add($"@{getParameterName(field)}", value);
var prop = recordType.GetProperty(field)!;
var propType = prop.PropertyType;
var value = prop.GetValue(record);
var dbType = value == null ? GetDbType(propType) : default;
query.Parameters.Add($"@{getParameterName(field)}", value, dbType);
}
return query;
@ -389,4 +389,10 @@ public static class ParameterizedQueryBuilderExtensions
return query;
}
private static DbType? GetDbType(Type type)
{
if (type == typeof(byte[])) return DbType.Binary;
return null;
}
}

View file

@ -17,9 +17,7 @@ public class DapperFeature : FeatureBase
public DapperFeature(IModule module) : base(module)
{
// See: https://learn.microsoft.com/en-us/dotnet/standard/data/sqlite/dapper-limitations#data-types
SqlMapper.AddTypeHandler(new DateTimeOffsetHandler());
SqlMapper.AddTypeHandler(new GuidHandler());
SqlMapper.AddTypeHandler(new TimeSpanHandler());
}
/// <summary>

View file

@ -18,11 +18,28 @@ public class DapperMigrationsFeature : FeatureBase
{
}
/// <summary>
/// Configures migrations to use SQLite.
/// </summary>
public DapperMigrationsFeature UseSqlite()
{
ConfigureRunner += runner => runner.AddSQLite();
return this;
}
/// <summary>
/// Configures migrations to use SQLite.
/// </summary>
public DapperMigrationsFeature UseSqlServer()
{
ConfigureRunner += runner => runner.AddSqlServer();
return this;
}
/// <summary>
/// Gets or sets a delegate to configure migrations.
/// </summary>
public Action<IMigrationRunnerBuilder> ConfigureRunner { get; set; } = runner => runner
.AddSQLite()
.WithGlobalConnectionString(sp => sp.GetRequiredService<IDbConnectionProvider>().GetConnectionString())
.WithMigrationsIn(typeof(Initial).Assembly);

View file

@ -1,6 +1,8 @@
using System.Data;
using Dapper;
using Elsa.Dapper.Contracts;
using Elsa.Dapper.Dialects;
using Elsa.Dapper.TypeHandlers.Sqlite;
using JetBrains.Annotations;
using Microsoft.Data.Sqlite;
@ -12,7 +14,14 @@ namespace Elsa.Dapper.Services;
[PublicAPI]
public class SqliteDbConnectionProvider : IDbConnectionProvider
{
private readonly string _connectionString = "Data Source=elsa.dapper.db";
private readonly string _connectionString = "Data Source=:memory:;Cache=Shared";
static SqliteDbConnectionProvider()
{
// See: https://learn.microsoft.com/en-us/dotnet/standard/data/sqlite/dapper-limitations#data-types
SqlMapper.AddTypeHandler(new DateTimeOffsetHandler());
SqlMapper.AddTypeHandler(new TimeSpanHandler());
}
/// <summary>
/// Initializes a new instance of the <see cref="SqliteDbConnectionProvider"/> class.
@ -29,9 +38,9 @@ public class SqliteDbConnectionProvider : IDbConnectionProvider
{
_connectionString = connectionString;
}
/// <inheritdoc />
public string GetConnectionString() =>_connectionString;
public string GetConnectionString() => _connectionString;
/// <inheritdoc />
public IDbConnection GetConnection()

View file

@ -264,7 +264,7 @@ public class Store<T> where T : notnull
filter(selectQuery);
selectQuery = selectQuery.OrderBy(orderFields.ToArray()).Page(pageArgs);
var deleteQuery = _dbConnectionProvider.CreateQuery().Delete(TableName, selectQuery);
var deleteQuery = _dbConnectionProvider.CreateQuery().Delete(TableName, primaryKey, selectQuery);
using var connection = _dbConnectionProvider.GetConnection();
return await deleteQuery.ExecuteAsync(connection);
}