mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-04 19:45:00 +03:00
fix: resolve JSON and SQLite trimming warnings (#10513)
Use generated JSON type metadata and propagate mapped SQLite types through CRUD and transactional bulk operations. Cover serialization options, affected counts, rollback and native test compatibility without changing UI models or persistence entities.
This commit is contained in:
committed by
GitHub
parent
aa00b2c614
commit
9a029a3f7e
@@ -0,0 +1,82 @@
|
||||
namespace ServiceLib.Tests.Common;
|
||||
|
||||
public class JsonUtilsMetadataTests
|
||||
{
|
||||
[Test]
|
||||
[Arguments(false, false)]
|
||||
[Arguments(false, true)]
|
||||
[Arguments(true, false)]
|
||||
[Arguments(true, true)]
|
||||
public async Task Serialize_PreservesIndentationNullsAndUnicode(bool indented, bool nullValue)
|
||||
{
|
||||
var item = new WebDavItem { Url = "https://example.com/русский", UserName = "tester" };
|
||||
|
||||
var json = JsonUtils.Serialize(item, indented, nullValue);
|
||||
var node = JsonUtils.ParseJson(json)!.AsObject();
|
||||
|
||||
await node["Url"]!.GetValue<string>().Should().BeEqualTo(item.Url);
|
||||
await json.Contains("русский").Should().BeTrue();
|
||||
await json.Contains(Environment.NewLine).Should().BeEqualTo(indented);
|
||||
await node.ContainsKey("Password").Should().BeEqualTo(nullValue);
|
||||
await node.ContainsKey("DirName").Should().BeEqualTo(nullValue);
|
||||
await JsonUtils.Deserialize<WebDavItem>(json)!.UserName.Should().BeEqualTo("tester");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Deserialize_AcceptsCommentsAndCaseInsensitiveNames()
|
||||
{
|
||||
const string json = "{/* existing configuration */ \"uRl\":\"https://example.com\",\"USERNAME\":\"tester\"}";
|
||||
var item = JsonUtils.Deserialize<WebDavItem>(json)!;
|
||||
|
||||
await item.Url.Should().BeEqualTo("https://example.com");
|
||||
await item.UserName.Should().BeEqualTo("tester");
|
||||
await JsonUtils.Deserialize<WebDavItem>("invalid").Should().BeNull();
|
||||
await JsonUtils.Deserialize<WebDavItem>(" ").Should().BeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task NodeAndCamelCaseSerialization_UseTheRequestedOptions()
|
||||
{
|
||||
var item = new WebDavItem { Url = "https://example.com" };
|
||||
var node = JsonUtils.SerializeToNode(item, nullValue: true)!.AsObject();
|
||||
var camelCase = JsonUtils.ParseJson(JsonUtils.SerializeCamelCase(item))!.AsObject();
|
||||
|
||||
await node.ContainsKey("Password").Should().BeTrue();
|
||||
await JsonUtils.SerializeToNode(item)!.AsObject().ContainsKey("Password").Should().BeFalse();
|
||||
await camelCase["url"]!.GetValue<string>().Should().BeEqualTo(item.Url);
|
||||
await camelCase.ContainsKey("Url").Should().BeFalse();
|
||||
await camelCase.ContainsKey("password").Should().BeFalse();
|
||||
|
||||
var values = JsonUtils.SerializeToArray(["first", "second"])!;
|
||||
await values.Count.Should().BeEqualTo(2);
|
||||
await values[0]!.GetValue<string>().Should().BeEqualTo("first");
|
||||
await values[1]!.GetValue<string>().Should().BeEqualTo("second");
|
||||
await JsonUtils.SerializeToArray(null).Should().BeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DeepCopy_KeepsProfileDataAndCreatesAnIndependentModel()
|
||||
{
|
||||
var item = new ProfileItem { IndexId = "profile", Address = "example.com", Port = 443, Remarks = "Original" };
|
||||
var copy = JsonUtils.DeepCopy(item)!;
|
||||
|
||||
await copy.IndexId.Should().BeEqualTo(item.IndexId);
|
||||
await copy.Address.Should().BeEqualTo(item.Address);
|
||||
await copy.Port.Should().BeEqualTo(443);
|
||||
copy.Remarks = "Changed";
|
||||
await item.Remarks.Should().BeEqualTo("Original");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task UnsupportedTypes_PreserveTheExistingFailureResults()
|
||||
{
|
||||
await JsonUtils.Serialize(new UnsupportedValue()).Should().BeEqualTo(string.Empty);
|
||||
await JsonUtils.SerializeCamelCase(new UnsupportedValue()).Should().BeEqualTo(string.Empty);
|
||||
await JsonUtils.Deserialize<UnsupportedValue>("{\"Name\":\"value\"}").Should().BeNull();
|
||||
}
|
||||
|
||||
private sealed class UnsupportedValue
|
||||
{
|
||||
public string Name { get; set; } = "value";
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,8 @@ public class CoreConfigV2rayServiceTests
|
||||
await headers["User-Agent"]!.GetValue<string>().Should().BeEqualTo("v2rayN");
|
||||
await headers["Set-Cookie"]!.AsArray()
|
||||
.Select(item => item!.GetValue<string>())
|
||||
.Should().BeEquivalentTo(["a=1", "b=2"]);
|
||||
.Order(StringComparer.Ordinal).SequenceEqual(["a=1", "b=2"])
|
||||
.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -67,11 +67,11 @@ public class HttpRequestHeadersHelperTests
|
||||
await oldHeaders.Count.Should().BeEqualTo(0);
|
||||
|
||||
item.RequestHeaders = "{\"X-hwid\":\"my_device\"}";
|
||||
database.Update(item);
|
||||
database.Update(item, typeof(SubItem));
|
||||
await database.Find<SubItem>(item.Id).RequestHeaders.Should().BeEqualTo(item.RequestHeaders);
|
||||
|
||||
item.RequestHeaders = "";
|
||||
database.Update(item);
|
||||
database.Update(item, typeof(SubItem));
|
||||
await database.Find<SubItem>(item.Id).RequestHeaders.Should().BeEqualTo("");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
namespace ServiceLib.Tests.Helper;
|
||||
|
||||
[NotInParallel]
|
||||
public class SQLiteHelperTests
|
||||
{
|
||||
private static readonly Lazy<SQLiteHelper> Database = new(() =>
|
||||
{
|
||||
var database = SQLiteHelper.Instance;
|
||||
database.CreateTable<HelperRow>();
|
||||
database.CreateTable<ReplacementRow>();
|
||||
database.CreateTable<DeleteAllRow>();
|
||||
database.CreateTable<NoPrimaryKeyRow>();
|
||||
return database;
|
||||
});
|
||||
|
||||
[Test]
|
||||
public async Task SingleWrites_ShouldPreserveValuesAndDeleteByPrimaryKey()
|
||||
{
|
||||
var database = Database.Value;
|
||||
var id = Guid.NewGuid().ToString("N");
|
||||
var row = new HelperRow { Id = id, Value = $"{id}-original" };
|
||||
try
|
||||
{
|
||||
await (await database.InsertAsync(row)).Should().BeEqualTo(1);
|
||||
await (await database.ReplaceAsync(new HelperRow { Id = id, Value = $"{id}-replacement" })).Should().BeEqualTo(1);
|
||||
row.Value = $"{id}-updated";
|
||||
await (await database.UpdateAsync(row)).Should().BeEqualTo(1);
|
||||
|
||||
var rows = await database.QueryAsync<HelperRow>($"SELECT * FROM SQLiteHelperTestRows WHERE Id = '{id}'");
|
||||
await rows.Count.Should().BeEqualTo(1);
|
||||
await rows[0].Value.Should().BeEqualTo($"{id}-updated");
|
||||
await (await database.TableAsync<HelperRow>().Where(item => item.Id == id).CountAsync()).Should().BeEqualTo(1);
|
||||
|
||||
row.Value = "not-the-stored-value";
|
||||
await (await database.DeleteAsync(row)).Should().BeEqualTo(1);
|
||||
await (await database.DeleteAsync(row)).Should().BeEqualTo(0);
|
||||
await (await database.TableAsync<HelperRow>().Where(item => item.Id == id).CountAsync()).Should().BeEqualTo(0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await database.ExecuteAsync($"DELETE FROM SQLiteHelperTestRows WHERE Id = '{id}'");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task BulkWrites_ShouldCommitEveryRowAndReturnAffectedCounts()
|
||||
{
|
||||
var database = Database.Value;
|
||||
var prefix = Guid.NewGuid().ToString("N");
|
||||
var rows = new[]
|
||||
{
|
||||
new HelperRow { Id = $"{prefix}-first", Value = $"{prefix}-original-first" },
|
||||
new HelperRow { Id = $"{prefix}-second", Value = $"{prefix}-original-second" },
|
||||
};
|
||||
try
|
||||
{
|
||||
await (await database.InsertAllAsync(rows)).Should().BeEqualTo(2);
|
||||
rows[0].Value = $"{prefix}-updated-first";
|
||||
rows[1].Value = $"{prefix}-updated-second";
|
||||
await (await database.UpdateAllAsync(rows)).Should().BeEqualTo(2);
|
||||
|
||||
var saved = await database.QueryAsync<HelperRow>($"SELECT * FROM SQLiteHelperTestRows WHERE Id LIKE '{prefix}%' ORDER BY Id");
|
||||
await saved.Count.Should().BeEqualTo(2);
|
||||
await saved[0].Value.Should().BeEqualTo($"{prefix}-updated-first");
|
||||
await saved[1].Value.Should().BeEqualTo($"{prefix}-updated-second");
|
||||
}
|
||||
finally
|
||||
{
|
||||
await database.ExecuteAsync($"DELETE FROM SQLiteHelperTestRows WHERE Id LIKE '{prefix}%'");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task InsertAllAsync_ShouldRollBackEarlierRowsWhenALaterInsertFails()
|
||||
{
|
||||
var database = Database.Value;
|
||||
var id = Guid.NewGuid().ToString("N");
|
||||
try
|
||||
{
|
||||
SQLiteException? error = null;
|
||||
try
|
||||
{
|
||||
await database.InsertAllAsync(new[]
|
||||
{
|
||||
new HelperRow { Id = id, Value = $"{id}-first" },
|
||||
new HelperRow { Id = id, Value = $"{id}-duplicate" },
|
||||
});
|
||||
}
|
||||
catch (SQLiteException exception)
|
||||
{
|
||||
error = exception;
|
||||
}
|
||||
|
||||
await error.Should().NotBeNull();
|
||||
await (await database.TableAsync<HelperRow>().Where(item => item.Id == id).CountAsync()).Should().BeEqualTo(0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await database.ExecuteAsync($"DELETE FROM SQLiteHelperTestRows WHERE Id = '{id}'");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task UpdateAllAsync_ShouldRollBackEarlierChangesWhenALaterUpdateFails()
|
||||
{
|
||||
var database = Database.Value;
|
||||
var prefix = Guid.NewGuid().ToString("N");
|
||||
var first = new HelperRow { Id = $"{prefix}-first", Value = $"{prefix}-original-first" };
|
||||
var second = new HelperRow { Id = $"{prefix}-second", Value = $"{prefix}-original-second" };
|
||||
try
|
||||
{
|
||||
await database.InsertAllAsync(new[] { first, second });
|
||||
first.Value = $"{prefix}-updated-first";
|
||||
second.Value = first.Value;
|
||||
SQLiteException? error = null;
|
||||
try
|
||||
{
|
||||
await database.UpdateAllAsync(new[] { first, second });
|
||||
}
|
||||
catch (SQLiteException exception)
|
||||
{
|
||||
error = exception;
|
||||
}
|
||||
|
||||
await error.Should().NotBeNull();
|
||||
var saved = await database.QueryAsync<HelperRow>($"SELECT * FROM SQLiteHelperTestRows WHERE Id LIKE '{prefix}%' ORDER BY Id");
|
||||
await saved.Count.Should().BeEqualTo(2);
|
||||
await saved[0].Value.Should().BeEqualTo($"{prefix}-original-first");
|
||||
await saved[1].Value.Should().BeEqualTo($"{prefix}-original-second");
|
||||
}
|
||||
finally
|
||||
{
|
||||
await database.ExecuteAsync($"DELETE FROM SQLiteHelperTestRows WHERE Id LIKE '{prefix}%'");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task EmptyBatches_ShouldReturnZero()
|
||||
{
|
||||
var database = Database.Value;
|
||||
await (await database.InsertAllAsync(Array.Empty<HelperRow>())).Should().BeEqualTo(0);
|
||||
await (await database.UpdateAllAsync(Array.Empty<HelperRow>())).Should().BeEqualTo(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DeleteAsync_ShouldRejectRowsWithoutAPrimaryKey()
|
||||
{
|
||||
var database = Database.Value;
|
||||
var value = Guid.NewGuid().ToString("N");
|
||||
try
|
||||
{
|
||||
var row = new NoPrimaryKeyRow { Value = value };
|
||||
await database.InsertAsync(row);
|
||||
NotSupportedException? error = null;
|
||||
try
|
||||
{
|
||||
await database.DeleteAsync(row);
|
||||
}
|
||||
catch (NotSupportedException exception)
|
||||
{
|
||||
error = exception;
|
||||
}
|
||||
|
||||
await error.Should().NotBeNull();
|
||||
await (await database.TableAsync<NoPrimaryKeyRow>().Where(item => item.Value == value).CountAsync()).Should().BeEqualTo(1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await database.ExecuteAsync($"DELETE FROM SQLiteHelperNoPrimaryKeyTestRows WHERE Value = '{value}'");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DeleteAllAsync_ShouldReturnTheNumberOfDeletedRows()
|
||||
{
|
||||
var database = Database.Value;
|
||||
await database.DeleteAllAsync<DeleteAllRow>();
|
||||
await database.InsertAllAsync(new[] { new DeleteAllRow { Id = "first" }, new DeleteAllRow { Id = "second" } });
|
||||
|
||||
await (await database.DeleteAllAsync<DeleteAllRow>()).Should().BeEqualTo(2);
|
||||
await (await database.TableAsync<DeleteAllRow>().CountAsync()).Should().BeEqualTo(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ReplaceAllAsync_ShouldInsertAndReplaceRowsAndReturnAffectedCounts()
|
||||
{
|
||||
var database = Database.Value;
|
||||
var prefix = Guid.NewGuid().ToString("N");
|
||||
var existing = new HelperRow { Id = $"{prefix}-existing", Value = $"{prefix}-original" };
|
||||
try
|
||||
{
|
||||
await database.InsertAsync(existing);
|
||||
var replacements = new[]
|
||||
{
|
||||
new HelperRow { Id = existing.Id, Value = $"{prefix}-updated" },
|
||||
new HelperRow { Id = $"{prefix}-new", Value = $"{prefix}-new-value" },
|
||||
};
|
||||
|
||||
await (await database.ReplaceAllAsync(replacements)).Should().BeEqualTo(2);
|
||||
await (await database.ReplaceAllAsync(replacements)).Should().BeEqualTo(2);
|
||||
var saved = await database.QueryAsync<HelperRow>($"SELECT * FROM SQLiteHelperTestRows WHERE Id LIKE '{prefix}%' ORDER BY Id");
|
||||
|
||||
await saved.Count.Should().BeEqualTo(2);
|
||||
await saved[0].Value.Should().BeEqualTo($"{prefix}-updated");
|
||||
await saved[1].Value.Should().BeEqualTo($"{prefix}-new-value");
|
||||
await (await database.ReplaceAllAsync(Array.Empty<HelperRow>())).Should().BeEqualTo(0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await database.ExecuteAsync($"DELETE FROM SQLiteHelperTestRows WHERE Id LIKE '{prefix}%'");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ReplaceAllAsync_ShouldRollBackReplacementsAndInsertsWhenALaterRowFails()
|
||||
{
|
||||
var database = Database.Value;
|
||||
var prefix = Guid.NewGuid().ToString("N");
|
||||
var existing = new ReplacementRow { Id = $"{prefix}-existing", Value = "original" };
|
||||
try
|
||||
{
|
||||
await database.InsertAsync(existing);
|
||||
SQLiteException? error = null;
|
||||
try
|
||||
{
|
||||
await database.ReplaceAllAsync(new[]
|
||||
{
|
||||
new ReplacementRow { Id = existing.Id, Value = "replacement" },
|
||||
new ReplacementRow { Id = $"{prefix}-new", Value = "inserted" },
|
||||
new ReplacementRow { Id = $"{prefix}-invalid", Value = null! },
|
||||
});
|
||||
}
|
||||
catch (SQLiteException exception)
|
||||
{
|
||||
error = exception;
|
||||
}
|
||||
|
||||
await error.Should().NotBeNull();
|
||||
var saved = await database.QueryAsync<ReplacementRow>($"SELECT * FROM SQLiteHelperReplaceAllTestRows WHERE Id LIKE '{prefix}%'");
|
||||
await saved.Count.Should().BeEqualTo(1);
|
||||
await saved[0].Id.Should().BeEqualTo(existing.Id);
|
||||
await saved[0].Value.Should().BeEqualTo("original");
|
||||
}
|
||||
finally
|
||||
{
|
||||
await database.ExecuteAsync($"DELETE FROM SQLiteHelperReplaceAllTestRows WHERE Id LIKE '{prefix}%'");
|
||||
}
|
||||
}
|
||||
|
||||
[Table("SQLiteHelperTestRows")]
|
||||
public class HelperRow
|
||||
{
|
||||
[PrimaryKey]
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
[Unique]
|
||||
public string Value { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[Table("SQLiteHelperDeleteAllTestRows")]
|
||||
public class DeleteAllRow
|
||||
{
|
||||
[PrimaryKey]
|
||||
public string Id { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[Table("SQLiteHelperReplaceAllTestRows")]
|
||||
public class ReplacementRow
|
||||
{
|
||||
[PrimaryKey]
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
[NotNull]
|
||||
public string Value { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[Table("SQLiteHelperNoPrimaryKeyTestRows")]
|
||||
public class NoPrimaryKeyRow
|
||||
{
|
||||
public string Value { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,6 @@ public class ClashProxiesViewModelTests
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await _cancellation.CancelAsync();
|
||||
_listener.Stop();
|
||||
try
|
||||
{
|
||||
await _serverTask;
|
||||
@@ -106,6 +105,7 @@ public class ClashProxiesViewModelTests
|
||||
}
|
||||
finally
|
||||
{
|
||||
_listener.Stop();
|
||||
_cancellation.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
|
||||
namespace ServiceLib.Common;
|
||||
|
||||
public class JsonUtils
|
||||
@@ -77,7 +79,7 @@ public class JsonUtils
|
||||
{
|
||||
return default;
|
||||
}
|
||||
return JsonSerializer.Deserialize<T>(strJson, _defaultDeserializeOptions);
|
||||
return JsonSerializer.Deserialize(strJson, (JsonTypeInfo<T>)_defaultDeserializeOptions.GetTypeInfo(typeof(T)));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -130,7 +132,7 @@ public class JsonUtils
|
||||
(false, true) => _defaultSerializeOptions,
|
||||
_ => _defaultSerializeNoIndentedOptions
|
||||
};
|
||||
result = JsonSerializer.Serialize(obj, options);
|
||||
result = JsonSerializer.Serialize(obj, (JsonTypeInfo<T>)options.GetTypeInfo(typeof(T)));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -161,7 +163,7 @@ public class JsonUtils
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
TypeInfoResolver = AppJsonContext.Default,
|
||||
};
|
||||
result = JsonSerializer.Serialize(obj, options);
|
||||
result = JsonSerializer.Serialize(obj, (JsonTypeInfo<T>)options.GetTypeInfo(typeof(T)));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -179,7 +181,7 @@ public class JsonUtils
|
||||
public static JsonNode? SerializeToNode<T>(T? obj, bool nullValue = false)
|
||||
{
|
||||
var options = nullValue ? _nullValueSerializeOptions : _defaultSerializeOptions;
|
||||
return JsonSerializer.SerializeToNode(obj, options);
|
||||
return JsonSerializer.SerializeToNode(obj, (JsonTypeInfo<T>)options.GetTypeInfo(typeof(T)));
|
||||
}
|
||||
|
||||
public static JsonArray? SerializeToArray(IEnumerable<string>? values)
|
||||
@@ -191,7 +193,7 @@ public class JsonUtils
|
||||
var array = new JsonArray();
|
||||
foreach (var value in values)
|
||||
{
|
||||
var valueNode = JsonSerializer.SerializeToNode(value, _defaultSerializeOptions);
|
||||
var valueNode = JsonSerializer.SerializeToNode(value, (JsonTypeInfo<string>)_defaultSerializeOptions.GetTypeInfo(typeof(string)));
|
||||
array.Add(valueNode);
|
||||
}
|
||||
return array;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ServiceLib.Helper;
|
||||
|
||||
@@ -18,47 +18,73 @@ public sealed class SQLiteHelper
|
||||
_dbAsync = new SQLiteAsyncConnection(_connstr, false);
|
||||
}
|
||||
|
||||
public CreateTableResult CreateTable<T>()
|
||||
public CreateTableResult CreateTable<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
|
||||
{
|
||||
return _db.CreateTable<T>();
|
||||
}
|
||||
|
||||
public async Task<int> InsertAllAsync(IEnumerable models)
|
||||
public async Task<int> InsertAllAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(IEnumerable<T> models)
|
||||
{
|
||||
return await _dbAsync.InsertAllAsync(models, runInTransaction: true).ConfigureAwait(false);
|
||||
var count = 0;
|
||||
await _dbAsync.RunInTransactionAsync(connection =>
|
||||
{
|
||||
foreach (var model in models)
|
||||
{
|
||||
count += connection.Insert(model, typeof(T));
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
return count;
|
||||
}
|
||||
|
||||
public async Task<int> ReplaceAllAsync(IEnumerable models)
|
||||
public async Task<int> ReplaceAllAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(IEnumerable<T> models)
|
||||
{
|
||||
return await _dbAsync.InsertAllAsync(models, extra: "OR REPLACE", runInTransaction: true).ConfigureAwait(false);
|
||||
var count = 0;
|
||||
await _dbAsync.RunInTransactionAsync(connection =>
|
||||
{
|
||||
foreach (var model in models)
|
||||
{
|
||||
count += connection.InsertOrReplace(model, typeof(T));
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
return count;
|
||||
}
|
||||
|
||||
public async Task<int> InsertAsync(object model)
|
||||
public async Task<int> InsertAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(T model)
|
||||
{
|
||||
return await _dbAsync.InsertAsync(model);
|
||||
return await _dbAsync.InsertAsync(model, typeof(T));
|
||||
}
|
||||
|
||||
public async Task<int> ReplaceAsync(object model)
|
||||
public async Task<int> ReplaceAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(T model)
|
||||
{
|
||||
return await _dbAsync.InsertOrReplaceAsync(model);
|
||||
return await _dbAsync.InsertOrReplaceAsync(model, typeof(T));
|
||||
}
|
||||
|
||||
public async Task<int> UpdateAsync(object model)
|
||||
public async Task<int> UpdateAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(T model)
|
||||
{
|
||||
return await _dbAsync.UpdateAsync(model);
|
||||
return await _dbAsync.UpdateAsync(model, typeof(T));
|
||||
}
|
||||
|
||||
public async Task<int> UpdateAllAsync(IEnumerable models)
|
||||
public async Task<int> UpdateAllAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(IEnumerable<T> models)
|
||||
{
|
||||
return await _dbAsync.UpdateAllAsync(models, runInTransaction: true).ConfigureAwait(false);
|
||||
var count = 0;
|
||||
await _dbAsync.RunInTransactionAsync(connection =>
|
||||
{
|
||||
foreach (var model in models)
|
||||
{
|
||||
count += connection.Update(model, typeof(T));
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
return count;
|
||||
}
|
||||
|
||||
public async Task<int> DeleteAsync(object model)
|
||||
public async Task<int> DeleteAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(T model)
|
||||
{
|
||||
return await _dbAsync.DeleteAsync(model);
|
||||
var mapping = await _dbAsync.GetMappingAsync(typeof(T));
|
||||
var primaryKey = mapping.PK ?? throw new NotSupportedException($"Cannot delete {mapping.TableName}: it has no PK");
|
||||
return await _dbAsync.DeleteAsync(primaryKey.GetValue(model), mapping);
|
||||
}
|
||||
|
||||
public async Task<int> DeleteAllAsync<T>()
|
||||
public async Task<int> DeleteAllAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
|
||||
{
|
||||
return await _dbAsync.DeleteAllAsync<T>();
|
||||
}
|
||||
@@ -68,12 +94,12 @@ public sealed class SQLiteHelper
|
||||
return await _dbAsync.ExecuteAsync(sql);
|
||||
}
|
||||
|
||||
public async Task<List<T>> QueryAsync<T>(string sql) where T : new()
|
||||
public async Task<List<T>> QueryAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(string sql) where T : new()
|
||||
{
|
||||
return await _dbAsync.QueryAsync<T>(sql);
|
||||
}
|
||||
|
||||
public AsyncTableQuery<T> TableAsync<T>() where T : new()
|
||||
public AsyncTableQuery<T> TableAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() where T : new()
|
||||
{
|
||||
return _dbAsync.Table<T>();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user