diff --git a/LiteDB.Benchmarks/Benchmarks/Insertion/InsertionIgnoreExpressionPropertyBenchmark.cs b/LiteDB.Benchmarks/Benchmarks/Insertion/InsertionIgnoreExpressionPropertyBenchmark.cs index 468e5ac05..057de0b6d 100644 --- a/LiteDB.Benchmarks/Benchmarks/Insertion/InsertionIgnoreExpressionPropertyBenchmark.cs +++ b/LiteDB.Benchmarks/Benchmarks/Insertion/InsertionIgnoreExpressionPropertyBenchmark.cs @@ -93,5 +93,94 @@ public void GlobalCleanup() File.Delete(DatabasePath); } - } + } + + + [BenchmarkCategory(Constants.Categories.INSERTION)] + public class InsertionIgnoreExpressionPropertyComponentModelBenchmark : BenchmarkBase + { + private List _baseData; + private List _baseDataWithBsonIgnore; + + private ILiteCollection _fileMetaCollection; + private ILiteCollection _fileMetaExclusionCollection; + + [GlobalSetup(Target = nameof(Insertion))] + public void GlobalBsonIgnoreSetup() + { + File.Delete(DatabasePath); + + DatabaseInstance = new LiteDatabase(ConnectionString()); + _fileMetaCollection = DatabaseInstance.GetCollection(); + _fileMetaCollection.EnsureIndex(fileMeta => fileMeta.ShouldBeShown); + + _baseData = FileMetaGeneratorComponentModel.GenerateList(DatasetSize); // executed once per each N value + } + + [GlobalSetup(Target = nameof(InsertionWithBsonIgnore))] + public void GlobalIgnorePropertySetup() + { + File.Delete(DatabasePath); + + DatabaseInstance = new LiteDatabase(ConnectionString()); + _fileMetaExclusionCollection = DatabaseInstance.GetCollection(); + _fileMetaExclusionCollection.EnsureIndex(fileMeta => fileMeta.ShouldBeShown); + + _baseDataWithBsonIgnore = FileMetaGeneratorComponentModel.GenerateList(DatasetSize); // executed once per each N value + } + + [Benchmark(Baseline = true)] + public int Insertion() + { + var count = _fileMetaCollection.Insert(_baseData); + DatabaseInstance.Checkpoint(); + return count; + } + + [Benchmark] + public int InsertionWithBsonIgnore() + { + var count = _fileMetaExclusionCollection.Insert(_baseDataWithBsonIgnore); + DatabaseInstance.Checkpoint(); + return count; + } + + [IterationCleanup] + public void IterationCleanup() + { + var indexesCollection = DatabaseInstance.GetCollection("$indexes"); + var droppedCollectionIndexes = indexesCollection.Query().Where(x => x["name"] != "_id").ToDocuments().ToList(); + + var collectionNames = DatabaseInstance.GetCollectionNames(); + foreach (var name in collectionNames) + { + DatabaseInstance.DropCollection(name); + } + + foreach (var indexInfo in droppedCollectionIndexes) + { + DatabaseInstance.GetCollection(indexInfo["collection"]) + .EnsureIndex(indexInfo["name"], BsonExpression.Create(indexInfo["expression"]), indexInfo["unique"]); + } + + DatabaseInstance.Checkpoint(); + DatabaseInstance.Rebuild(); + } + + [GlobalCleanup] + public void GlobalCleanup() + { + _baseData?.Clear(); + _baseData = null; + + _baseDataWithBsonIgnore?.Clear(); + _baseDataWithBsonIgnore = null; + + DatabaseInstance?.Checkpoint(); + DatabaseInstance?.Dispose(); + DatabaseInstance = null; + + File.Delete(DatabasePath); + } + } } \ No newline at end of file diff --git a/LiteDB.Benchmarks/Models/FileMetaBase.cs b/LiteDB.Benchmarks/Models/FileMetaBase.cs index 15b7f63aa..23bb94741 100644 --- a/LiteDB.Benchmarks/Models/FileMetaBase.cs +++ b/LiteDB.Benchmarks/Models/FileMetaBase.cs @@ -2,6 +2,7 @@ namespace LiteDB.Benchmarks.Models { + public class FileMetaBase { [BsonIgnore] diff --git a/LiteDB.Benchmarks/Models/FileMetaBaseComponentModel.cs b/LiteDB.Benchmarks/Models/FileMetaBaseComponentModel.cs new file mode 100644 index 000000000..29bddb434 --- /dev/null +++ b/LiteDB.Benchmarks/Models/FileMetaBaseComponentModel.cs @@ -0,0 +1,37 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace LiteDB.Benchmarks.Models +{ + public class FileMetaBaseComponentModel + { + [NotMapped] + public const string BsonIdPropertyKey = "_id"; + + [Key] + public virtual string Id => $"{FileId}_{Version}"; + + public Guid FileId { get; set; } + + public string ParentId { get; set; } + + public string Title { get; set; } + + public string MimeType { get; set; } + + public int Version { get; set; } + + public DateTimeOffset? ValidFrom { get; set; } + + public DateTimeOffset? ValidTo { get; set; } + + public bool IsFavorite { get; set; } + + public bool ShouldBeShown { get; set; } + + public float[] Vectors { get; set; } + + public virtual bool IsValid => ValidFrom == null || ValidFrom <= DateTimeOffset.UtcNow && ValidTo == null || ValidTo > DateTimeOffset.UtcNow; + } +} \ No newline at end of file diff --git a/LiteDB.Benchmarks/Models/FileMetaWithExclusionComponentModel.cs b/LiteDB.Benchmarks/Models/FileMetaWithExclusionComponentModel.cs new file mode 100644 index 000000000..38310639f --- /dev/null +++ b/LiteDB.Benchmarks/Models/FileMetaWithExclusionComponentModel.cs @@ -0,0 +1,27 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace LiteDB.Benchmarks.Models +{ + public class FileMetaWithExclusionComponentModel : FileMetaBaseComponentModel + { + public FileMetaWithExclusionComponentModel() + { + } + + public FileMetaWithExclusionComponentModel(FileMetaBaseComponentModel fileMetaBase) + { + FileId = fileMetaBase.FileId; + ParentId = fileMetaBase.ParentId; + Title = fileMetaBase.Title; + MimeType = fileMetaBase.MimeType; + Version = fileMetaBase.Version; + ValidFrom = fileMetaBase.ValidFrom; + ValidTo = fileMetaBase.ValidTo; + IsFavorite = fileMetaBase.IsFavorite; + ShouldBeShown = fileMetaBase.ShouldBeShown; + } + + [NotMapped] + public override bool IsValid => base.IsValid; + } +} \ No newline at end of file diff --git a/LiteDB.Benchmarks/Models/Generators/FileMetaGenerator.cs b/LiteDB.Benchmarks/Models/Generators/FileMetaGenerator.cs index 903597882..280b356d6 100644 --- a/LiteDB.Benchmarks/Models/Generators/FileMetaGenerator.cs +++ b/LiteDB.Benchmarks/Models/Generators/FileMetaGenerator.cs @@ -10,8 +10,8 @@ namespace LiteDB.Benchmarks.Models.Generators private static T Generate() { - var docGuid = Guid.NewGuid(); - + var docGuid = Guid.NewGuid(); + var generatedFileMeta = new T { FileId = docGuid, @@ -20,7 +20,7 @@ private static T Generate() MimeType = "application/pdf", IsFavorite = _random.Next(10) >= 9, ShouldBeShown = _random.Next(10) >= 7, - Vectors = Enumerable.Range(0, 128).Select(_ => (float)_random.NextDouble()).ToArray() + Vectors = Enumerable.Range(0, 128).Select(_ => (float)_random.NextDouble()).ToArray() }; if (_random.Next(10) >= 5) diff --git a/LiteDB.Benchmarks/Models/Generators/FileMetaGeneratorComponentModel.cs b/LiteDB.Benchmarks/Models/Generators/FileMetaGeneratorComponentModel.cs new file mode 100644 index 000000000..365d422cc --- /dev/null +++ b/LiteDB.Benchmarks/Models/Generators/FileMetaGeneratorComponentModel.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace LiteDB.Benchmarks.Models.Generators +{ + public static class FileMetaGeneratorComponentModel where T : FileMetaBaseComponentModel, new() + { + private static Random _random; + + private static T Generate() + { + var docGuid = Guid.NewGuid(); + + var generatedFileMeta = new T + { + FileId = docGuid, + Version = _random.Next(5), + Title = $"Document-{docGuid}", + MimeType = "application/pdf", + IsFavorite = _random.Next(10) >= 9, + ShouldBeShown = _random.Next(10) >= 7, + Vectors = Enumerable.Range(0, 128).Select(_ => (float)_random.NextDouble()).ToArray() + }; + + if (_random.Next(10) >= 5) + { + generatedFileMeta.ValidFrom = DateTimeOffset.Now.AddDays(-20 + _random.Next(40)); + generatedFileMeta.ValidFrom = DateTimeOffset.UtcNow.AddDays(-10 + _random.Next(40)); + } + + return generatedFileMeta; + } + + public static List GenerateList(int amountToGenerate) + { + _random = new Random(0); + + var generatedList = new List(); + for (var i = 0; i < amountToGenerate; i++) generatedList.Add(Generate()); + + foreach (var fileMeta in generatedList) + { + if (_random.Next(100) <= 1) + { + continue; + } + + fileMeta.ParentId = generatedList[_random.Next(amountToGenerate)].Id; + } + + return generatedList; + } + } +} \ No newline at end of file diff --git a/LiteDB.Tests/Mapper/CustomMapping_Tests.cs b/LiteDB.Tests/Mapper/CustomMapping_Tests.cs index 50b42d032..a1bb41888 100644 --- a/LiteDB.Tests/Mapper/CustomMapping_Tests.cs +++ b/LiteDB.Tests/Mapper/CustomMapping_Tests.cs @@ -1,67 +1,133 @@ -using System; -using System.Collections.Generic; -using FluentAssertions; -using Xunit; - -namespace LiteDB.Tests.Mapper -{ - public class CustomMappingCtor_Tests - { - public class UserWithCustomId - { - public int Key { get; } - public string Name { get; } - - public UserWithCustomId(int key, string name) - { - this.Key = key; - this.Name = name; - } - } - - [Fact] - public void Custom_Ctor_With_Custom_Id() - { - var mapper = new BsonMapper(); - - mapper.Entity() - .Id(u => u.Key, false); - - var doc = new BsonDocument { ["_id"] = 10, ["name"] = "John" }; - - var user = mapper.ToObject(doc); - - user.Key.Should().Be(10); // Expected user.Key to be 10, but found 0. - user.Name.Should().Be("John"); - } - - public abstract class BaseClass - { - [BsonId] - public string CustomId { get; set; } - - [BsonField("CustomName")] - public string Name { get; set; } - } - - public class ConcreteClass : BaseClass - { - - } - - [Fact] - public void Custom_Id_In_Interface() - { - var mapper = new BsonMapper(); - - var obj = new ConcreteClass { CustomId = "myid", Name = "myname" }; - var doc = mapper.Serialize(obj) as BsonDocument; - doc["_id"].Should().NotBeNull(); - doc["_id"].Should().Be("myid"); - doc["CustomName"].Should().NotBe(BsonValue.Null); - doc["CustomName"].Should().Be("myname"); - doc["Name"].Should().Be(BsonValue.Null); - doc.Keys.ExpectCount(2); - } - } +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using FluentAssertions; +using Xunit; + +namespace LiteDB.Tests.Mapper +{ + public class CustomMappingCtor_Tests + { + public class UserWithCustomId + { + public int Key { get; } + public string Name { get; } + + public UserWithCustomId(int key, string name) + { + this.Key = key; + this.Name = name; + } + } + + [Fact] + public void Custom_Ctor_With_Custom_Id() + { + var mapper = new BsonMapper(); + + mapper.Entity() + .Id(u => u.Key, false); + + var doc = new BsonDocument { ["_id"] = 10, ["name"] = "John" }; + + var user = mapper.ToObject(doc); + + user.Key.Should().Be(10); // Ensure that the custom mapping sets the Key property from the _id field. +            user.Name.Should().Be("John"); + } + + public abstract class BaseClass + { + [BsonId] + public string CustomId { get; set; } + + [BsonField("CustomName")] + public string Name { get; set; } + } + + public class ConcreteClass : BaseClass + { + + } + + [Fact] + public void Custom_Id_In_Interface() + { + var mapper = new BsonMapper(); + + var obj = new ConcreteClass { CustomId = "myid", Name = "myname" }; + var doc = mapper.Serialize(obj) as BsonDocument; + doc["_id"].Should().NotBeNull(); + doc["_id"].Should().Be("myid"); + doc["CustomName"].Should().NotBe(BsonValue.Null); + doc["CustomName"].Should().Be("myname"); + doc["Name"].Should().Be(BsonValue.Null); + doc.Keys.ExpectCount(2); + } + + public class ClassWithBsonIgnore + { + public int Id { get; set; } + public string Keep { get; set; } + [BsonIgnore] + public string Ignore { get; set; } + } + + [Fact] + public void Test_BsonIgnoreAttribute() + { + var mapper = new BsonMapper(); + var obj = new ClassWithBsonIgnore { Id = 1, Keep = "K", Ignore = "I" }; + var doc = mapper.Serialize(obj) as BsonDocument; + + doc["_id"].Should().Be(1); + doc["Keep"].Should().Be("K"); + doc.ContainsKey("Ignore").Should().BeFalse(); + doc.Keys.ExpectCount(2); + } + +#if NET8_0_OR_GREATER + + public class ClassWithKeyAttribute + { + [Key] + public int MyKey { get; set; } + public string Value { get; set; } + } + + [Fact] + public void Test_KeyAttribute_As_BsonId() + { + var mapper = new BsonMapper(); + var obj = new ClassWithKeyAttribute { MyKey = 123, Value = "abc" }; + var doc = mapper.Serialize(obj) as BsonDocument; + + doc["_id"].Should().Be(123); + doc["Value"].Should().Be("abc"); + doc.Keys.ExpectCount(2); + } + + public class ClassWithNotMappedAttribute + { + public int Id { get; set; } + public string Keep { get; set; } + [NotMapped] + public string Ignore { get; set; } + } + + [Fact] + public void Test_NotMappedAttribute_As_BsonIgnore() + { + var mapper = new BsonMapper(); + var obj = new ClassWithNotMappedAttribute { Id = 1, Keep = "K", Ignore = "I" }; + var doc = mapper.Serialize(obj) as BsonDocument; + + doc["_id"].Should().Be(1); + doc["Keep"].Should().Be("K"); + doc.ContainsKey("Ignore").Should().BeFalse(); + doc.Keys.ExpectCount(2); + } +#endif + } } \ No newline at end of file diff --git a/LiteDB.sln b/LiteDB.sln index 7f0051124..6fdae1ec1 100644 --- a/LiteDB.sln +++ b/LiteDB.sln @@ -1,182 +1,230 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.1.32328.378 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiteDB", "LiteDB\LiteDB.csproj", "{9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiteDB.Tests", "LiteDB.Tests\LiteDB.Tests.csproj", "{74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiteDB.Shell", "LiteDB.Shell\LiteDB.Shell.csproj", "{99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiteDB.Benchmarks", "LiteDB.Benchmarks\LiteDB.Benchmarks.csproj", "{DF9C82C1-446F-458A-AA50-78E58BA17273}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiteDB.Stress", "LiteDB.Stress\LiteDB.Stress.csproj", "{FFBC5669-DA32-4907-8793-7B414279DA3B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiteDB.Demo.Tools.VectorSearch", "LiteDB.Demo.Tools.VectorSearch\LiteDB.Demo.Tools.VectorSearch.csproj", "{64EEF08C-CE83-4929-B5E4-583BBC332941}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp1", "ConsoleApp1\ConsoleApp1.csproj", "{E8763934-E46A-4AAF-A2B5-E812016DAF84}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Issue_2586_RollbackTransaction", "LiteDB.ReproRunner\Repros\Issue_2586_RollbackTransaction\Issue_2586_RollbackTransaction.csproj", "{BE1D6CA2-134A-404A-8F1A-C48E4E240159}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{D455AC29-7847-4DF4-AD06-69042F8B8885}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LiteDB.ReproRunner", "LiteDB.ReproRunner", "{C172DFBD-9BFC-41A4-82B9-5B9BBC90850D}" - ProjectSection(SolutionItems) = preProject - LiteDB.ReproRunner\README.md = LiteDB.ReproRunner\README.md - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiteDB.ReproRunner.Cli", "LiteDB.ReproRunner\LiteDB.ReproRunner.Cli\LiteDB.ReproRunner.Cli.csproj", "{CDCF5EED-50F3-4790-B180-10B203EE6B4B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Repros", "Repros", "{B0BD59D3-0D10-42BF-A744-533473577C8C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Issue_2561_TransactionMonitor", "LiteDB.ReproRunner\Repros\Issue_2561_TransactionMonitor\Issue_2561_TransactionMonitor.csproj", "{B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3B786621-2B82-4C69-8FE9-3889ECB36E75}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiteDB.ReproRunner.Tests", "LiteDB.ReproRunner.Tests\LiteDB.ReproRunner.Tests.csproj", "{3EF8E506-B57B-4A98-AD09-E687F9DC515D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiteDB.ReproRunner.Shared", "LiteDB.ReproRunner\LiteDB.ReproRunner.Shared\LiteDB.ReproRunner.Shared.csproj", "{CE109129-4017-46E7-BE84-17D4D83296F4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedMutexHarness", "LiteDB.Tests.SharedMutexHarness\SharedMutexHarness.csproj", "{F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|x64.ActiveCfg = Debug|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|x64.Build.0 = Debug|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|x86.ActiveCfg = Debug|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|x86.Build.0 = Debug|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|Any CPU.Build.0 = Release|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|x64.ActiveCfg = Release|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|x64.Build.0 = Release|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|x86.ActiveCfg = Release|Any CPU - {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|x86.Build.0 = Release|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|x64.ActiveCfg = Debug|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|x64.Build.0 = Debug|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|x86.ActiveCfg = Debug|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|x86.Build.0 = Debug|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|Any CPU.Build.0 = Release|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|x64.ActiveCfg = Release|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|x64.Build.0 = Release|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|x86.ActiveCfg = Release|Any CPU - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|x86.Build.0 = Release|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|Any CPU.Build.0 = Debug|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|x64.ActiveCfg = Debug|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|x64.Build.0 = Debug|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|x86.ActiveCfg = Debug|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|x86.Build.0 = Debug|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|Any CPU.ActiveCfg = Release|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|Any CPU.Build.0 = Release|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|x64.ActiveCfg = Release|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|x64.Build.0 = Release|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|x86.ActiveCfg = Release|Any CPU - {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|x86.Build.0 = Release|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|x64.ActiveCfg = Debug|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|x64.Build.0 = Debug|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|x86.ActiveCfg = Debug|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|x86.Build.0 = Debug|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|Any CPU.Build.0 = Release|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|x64.ActiveCfg = Release|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|x64.Build.0 = Release|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|x86.ActiveCfg = Release|Any CPU - {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|x86.Build.0 = Release|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|x64.ActiveCfg = Debug|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|x64.Build.0 = Debug|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|x86.ActiveCfg = Debug|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|x86.Build.0 = Debug|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|Any CPU.Build.0 = Release|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|x64.ActiveCfg = Release|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|x64.Build.0 = Release|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|x86.ActiveCfg = Release|Any CPU - {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|x86.Build.0 = Release|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|Any CPU.Build.0 = Debug|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|x64.ActiveCfg = Debug|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|x64.Build.0 = Debug|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|x86.ActiveCfg = Debug|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|x86.Build.0 = Debug|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|Any CPU.ActiveCfg = Release|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|Any CPU.Build.0 = Release|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|x64.ActiveCfg = Release|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|x64.Build.0 = Release|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|x86.ActiveCfg = Release|Any CPU - {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|x86.Build.0 = Release|Any CPU - {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Release|Any CPU.Build.0 = Release|Any CPU - {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Release|Any CPU.Build.0 = Release|Any CPU - {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Release|Any CPU.Build.0 = Release|Any CPU - {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Release|Any CPU.Build.0 = Release|Any CPU - {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Release|Any CPU.Build.0 = Release|Any CPU - {CE109129-4017-46E7-BE84-17D4D83296F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE109129-4017-46E7-BE84-17D4D83296F4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE109129-4017-46E7-BE84-17D4D83296F4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE109129-4017-46E7-BE84-17D4D83296F4}.Release|Any CPU.Build.0 = Release|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|x64.ActiveCfg = Debug|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|x64.Build.0 = Debug|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|x86.ActiveCfg = Debug|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|x86.Build.0 = Debug|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|Any CPU.Build.0 = Release|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|x64.ActiveCfg = Release|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|x64.Build.0 = Release|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|x86.ActiveCfg = Release|Any CPU - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {45099B85-2AE1-434B-913A-6AD14FD3AF4A} - EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {E8763934-E46A-4AAF-A2B5-E812016DAF84} = {D455AC29-7847-4DF4-AD06-69042F8B8885} - {CDCF5EED-50F3-4790-B180-10B203EE6B4B} = {C172DFBD-9BFC-41A4-82B9-5B9BBC90850D} - {B0BD59D3-0D10-42BF-A744-533473577C8C} = {C172DFBD-9BFC-41A4-82B9-5B9BBC90850D} - {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC} = {B0BD59D3-0D10-42BF-A744-533473577C8C} - {3EF8E506-B57B-4A98-AD09-E687F9DC515D} = {3B786621-2B82-4C69-8FE9-3889ECB36E75} - {CE109129-4017-46E7-BE84-17D4D83296F4} = {C172DFBD-9BFC-41A4-82B9-5B9BBC90850D} - {BE1D6CA2-134A-404A-8F1A-C48E4E240159} = {B0BD59D3-0D10-42BF-A744-533473577C8C} - {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA} = {3B786621-2B82-4C69-8FE9-3889ECB36E75} - {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6} = {3B786621-2B82-4C69-8FE9-3889ECB36E75} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32328.378 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiteDB", "LiteDB\LiteDB.csproj", "{9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiteDB.Tests", "LiteDB.Tests\LiteDB.Tests.csproj", "{74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiteDB.Shell", "LiteDB.Shell\LiteDB.Shell.csproj", "{99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiteDB.Benchmarks", "LiteDB.Benchmarks\LiteDB.Benchmarks.csproj", "{DF9C82C1-446F-458A-AA50-78E58BA17273}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiteDB.Stress", "LiteDB.Stress\LiteDB.Stress.csproj", "{FFBC5669-DA32-4907-8793-7B414279DA3B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiteDB.Demo.Tools.VectorSearch", "LiteDB.Demo.Tools.VectorSearch\LiteDB.Demo.Tools.VectorSearch.csproj", "{64EEF08C-CE83-4929-B5E4-583BBC332941}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp1", "ConsoleApp1\ConsoleApp1.csproj", "{E8763934-E46A-4AAF-A2B5-E812016DAF84}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Issue_2586_RollbackTransaction", "LiteDB.ReproRunner\Repros\Issue_2586_RollbackTransaction\Issue_2586_RollbackTransaction.csproj", "{BE1D6CA2-134A-404A-8F1A-C48E4E240159}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{D455AC29-7847-4DF4-AD06-69042F8B8885}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LiteDB.ReproRunner", "LiteDB.ReproRunner", "{C172DFBD-9BFC-41A4-82B9-5B9BBC90850D}" + ProjectSection(SolutionItems) = preProject + LiteDB.ReproRunner\README.md = LiteDB.ReproRunner\README.md + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiteDB.ReproRunner.Cli", "LiteDB.ReproRunner\LiteDB.ReproRunner.Cli\LiteDB.ReproRunner.Cli.csproj", "{CDCF5EED-50F3-4790-B180-10B203EE6B4B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Repros", "Repros", "{B0BD59D3-0D10-42BF-A744-533473577C8C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Issue_2561_TransactionMonitor", "LiteDB.ReproRunner\Repros\Issue_2561_TransactionMonitor\Issue_2561_TransactionMonitor.csproj", "{B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3B786621-2B82-4C69-8FE9-3889ECB36E75}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiteDB.ReproRunner.Tests", "LiteDB.ReproRunner.Tests\LiteDB.ReproRunner.Tests.csproj", "{3EF8E506-B57B-4A98-AD09-E687F9DC515D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiteDB.ReproRunner.Shared", "LiteDB.ReproRunner\LiteDB.ReproRunner.Shared\LiteDB.ReproRunner.Shared.csproj", "{CE109129-4017-46E7-BE84-17D4D83296F4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedMutexHarness", "LiteDB.Tests.SharedMutexHarness\SharedMutexHarness.csproj", "{F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|x64.ActiveCfg = Debug|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|x64.Build.0 = Debug|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|x86.ActiveCfg = Debug|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Debug|x86.Build.0 = Debug|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|Any CPU.Build.0 = Release|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|x64.ActiveCfg = Release|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|x64.Build.0 = Release|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|x86.ActiveCfg = Release|Any CPU + {9497DA19-1FCA-4C2E-A1AB-8DFAACBC76E1}.Release|x86.Build.0 = Release|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|x64.ActiveCfg = Debug|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|x64.Build.0 = Debug|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|x86.ActiveCfg = Debug|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Debug|x86.Build.0 = Debug|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|Any CPU.Build.0 = Release|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|x64.ActiveCfg = Release|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|x64.Build.0 = Release|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|x86.ActiveCfg = Release|Any CPU + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA}.Release|x86.Build.0 = Release|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|x64.ActiveCfg = Debug|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|x64.Build.0 = Debug|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|x86.ActiveCfg = Debug|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Debug|x86.Build.0 = Debug|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|Any CPU.Build.0 = Release|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|x64.ActiveCfg = Release|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|x64.Build.0 = Release|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|x86.ActiveCfg = Release|Any CPU + {99887C89-CAE4-4A8D-AC4B-87E28B9B1F87}.Release|x86.Build.0 = Release|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|x64.ActiveCfg = Debug|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|x64.Build.0 = Debug|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|x86.ActiveCfg = Debug|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Debug|x86.Build.0 = Debug|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|Any CPU.Build.0 = Release|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|x64.ActiveCfg = Release|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|x64.Build.0 = Release|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|x86.ActiveCfg = Release|Any CPU + {DF9C82C1-446F-458A-AA50-78E58BA17273}.Release|x86.Build.0 = Release|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|x64.ActiveCfg = Debug|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|x64.Build.0 = Debug|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|x86.ActiveCfg = Debug|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Debug|x86.Build.0 = Debug|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|Any CPU.Build.0 = Release|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|x64.ActiveCfg = Release|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|x64.Build.0 = Release|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|x86.ActiveCfg = Release|Any CPU + {FFBC5669-DA32-4907-8793-7B414279DA3B}.Release|x86.Build.0 = Release|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|x64.ActiveCfg = Debug|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|x64.Build.0 = Debug|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|x86.ActiveCfg = Debug|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Debug|x86.Build.0 = Debug|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|Any CPU.Build.0 = Release|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|x64.ActiveCfg = Release|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|x64.Build.0 = Release|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|x86.ActiveCfg = Release|Any CPU + {64EEF08C-CE83-4929-B5E4-583BBC332941}.Release|x86.Build.0 = Release|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Debug|x64.ActiveCfg = Debug|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Debug|x64.Build.0 = Debug|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Debug|x86.ActiveCfg = Debug|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Debug|x86.Build.0 = Debug|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Release|Any CPU.Build.0 = Release|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Release|x64.ActiveCfg = Release|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Release|x64.Build.0 = Release|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Release|x86.ActiveCfg = Release|Any CPU + {E8763934-E46A-4AAF-A2B5-E812016DAF84}.Release|x86.Build.0 = Release|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Debug|x64.ActiveCfg = Debug|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Debug|x64.Build.0 = Debug|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Debug|x86.ActiveCfg = Debug|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Debug|x86.Build.0 = Debug|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Release|Any CPU.Build.0 = Release|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Release|x64.ActiveCfg = Release|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Release|x64.Build.0 = Release|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Release|x86.ActiveCfg = Release|Any CPU + {BE1D6CA2-134A-404A-8F1A-C48E4E240159}.Release|x86.Build.0 = Release|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Debug|x64.ActiveCfg = Debug|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Debug|x64.Build.0 = Debug|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Debug|x86.ActiveCfg = Debug|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Debug|x86.Build.0 = Debug|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Release|Any CPU.Build.0 = Release|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Release|x64.ActiveCfg = Release|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Release|x64.Build.0 = Release|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Release|x86.ActiveCfg = Release|Any CPU + {CDCF5EED-50F3-4790-B180-10B203EE6B4B}.Release|x86.Build.0 = Release|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Debug|x64.ActiveCfg = Debug|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Debug|x64.Build.0 = Debug|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Debug|x86.ActiveCfg = Debug|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Debug|x86.Build.0 = Debug|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Release|Any CPU.Build.0 = Release|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Release|x64.ActiveCfg = Release|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Release|x64.Build.0 = Release|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Release|x86.ActiveCfg = Release|Any CPU + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC}.Release|x86.Build.0 = Release|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Debug|x64.ActiveCfg = Debug|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Debug|x64.Build.0 = Debug|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Debug|x86.ActiveCfg = Debug|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Debug|x86.Build.0 = Debug|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Release|Any CPU.Build.0 = Release|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Release|x64.ActiveCfg = Release|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Release|x64.Build.0 = Release|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Release|x86.ActiveCfg = Release|Any CPU + {3EF8E506-B57B-4A98-AD09-E687F9DC515D}.Release|x86.Build.0 = Release|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Debug|x64.ActiveCfg = Debug|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Debug|x64.Build.0 = Debug|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Debug|x86.ActiveCfg = Debug|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Debug|x86.Build.0 = Debug|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Release|Any CPU.Build.0 = Release|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Release|x64.ActiveCfg = Release|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Release|x64.Build.0 = Release|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Release|x86.ActiveCfg = Release|Any CPU + {CE109129-4017-46E7-BE84-17D4D83296F4}.Release|x86.Build.0 = Release|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|x64.ActiveCfg = Debug|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|x64.Build.0 = Debug|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|x86.ActiveCfg = Debug|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Debug|x86.Build.0 = Debug|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|Any CPU.Build.0 = Release|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|x64.ActiveCfg = Release|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|x64.Build.0 = Release|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|x86.ActiveCfg = Release|Any CPU + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {74E32E43-2A57-4A38-BD8C-9108B0DCAEAA} = {3B786621-2B82-4C69-8FE9-3889ECB36E75} + {E8763934-E46A-4AAF-A2B5-E812016DAF84} = {D455AC29-7847-4DF4-AD06-69042F8B8885} + {BE1D6CA2-134A-404A-8F1A-C48E4E240159} = {B0BD59D3-0D10-42BF-A744-533473577C8C} + {CDCF5EED-50F3-4790-B180-10B203EE6B4B} = {C172DFBD-9BFC-41A4-82B9-5B9BBC90850D} + {B0BD59D3-0D10-42BF-A744-533473577C8C} = {C172DFBD-9BFC-41A4-82B9-5B9BBC90850D} + {B5BF3DFE-5F26-447A-AF5A-60C6E3D341AC} = {B0BD59D3-0D10-42BF-A744-533473577C8C} + {3EF8E506-B57B-4A98-AD09-E687F9DC515D} = {3B786621-2B82-4C69-8FE9-3889ECB36E75} + {CE109129-4017-46E7-BE84-17D4D83296F4} = {C172DFBD-9BFC-41A4-82B9-5B9BBC90850D} + {F7E423B9-B90B-4F4D-B02A-F0101BBA26E6} = {3B786621-2B82-4C69-8FE9-3889ECB36E75} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {45099B85-2AE1-434B-913A-6AD14FD3AF4A} + EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection +EndGlobal diff --git a/LiteDB/Client/Mapper/BsonMapper.GetEntityMapper.cs b/LiteDB/Client/Mapper/BsonMapper.GetEntityMapper.cs index e3b122088..5cf26def1 100644 --- a/LiteDB/Client/Mapper/BsonMapper.GetEntityMapper.cs +++ b/LiteDB/Client/Mapper/BsonMapper.GetEntityMapper.cs @@ -1,253 +1,284 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Threading; - -namespace LiteDB; - -public partial class BsonMapper -{ - /// - /// Mapping cache between Class/BsonDocument - /// - private readonly ConcurrentDictionary _entities = new(); - - /// - /// Get property mapper between typed .NET class and BsonDocument - Cache results - /// - internal EntityMapper GetEntityMapper(Type type) - { - if (_entities.TryGetValue(type, out EntityMapper mapper)) - { - return mapper; - } - - using var cts = new CancellationTokenSource(); - try - { - // We need to add the empty shell, because ``BuildEntityMapper`` may use this method recursively - var newMapper = new EntityMapper(type, cts.Token); - mapper = _entities.GetOrAdd(type, newMapper); - if (ReferenceEquals(mapper, newMapper)) - { - try - { - this.BuildEntityMapper(mapper); - } - catch (Exception ex) - { - _entities.TryRemove(type, out _); - throw new LiteException(LiteException.MAPPING_ERROR, $"Error in '{type.Name}' mapping: {ex.Message}", ex); - } - } - } - finally - { - // Allow the Mapper to be used for de-/serialization - cts.Cancel(); - } - - return mapper; - } - - /// - /// Use this method to override how your class can be, by default, mapped from entity to Bson document. - /// Returns an EntityMapper from each requested Type - /// - protected void BuildEntityMapper(EntityMapper mapper) - { - var idAttr = typeof(BsonIdAttribute); - var ignoreAttr = typeof(BsonIgnoreAttribute); - var fieldAttr = typeof(BsonFieldAttribute); - var dbrefAttr = typeof(BsonRefAttribute); - - var members = this.GetTypeMembers(mapper.ForType); - var id = this.GetIdMember(members); - - foreach (var memberInfo in members) - { - // checks [BsonIgnore] - if (CustomAttributeExtensions.IsDefined(memberInfo, ignoreAttr, true)) continue; - - // checks field name conversion - var name = this.ResolveFieldName(memberInfo.Name); - - // check if property has [BsonField] - var field = (BsonFieldAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, fieldAttr, true) - .FirstOrDefault(); - - // check if property has [BsonField] with a custom field name - if (field != null && field.Name != null) - { - name = field.Name; - } - - // checks if memberInfo is id field - if (memberInfo == id) - { - name = "_id"; - } - - // create getter/setter function - var getter = Reflection.CreateGenericGetter(mapper.ForType, memberInfo); - var setter = Reflection.CreateGenericSetter(mapper.ForType, memberInfo); - - // check if property has [BsonId] to get with was setted AutoId = true - var autoId = (BsonIdAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, idAttr, true) - .FirstOrDefault(); - - // get data type - var dataType = memberInfo is PropertyInfo - ? (memberInfo as PropertyInfo).PropertyType - : (memberInfo as FieldInfo).FieldType; - - // check if datatype is list/array - var isEnumerable = Reflection.IsEnumerable(dataType); - - // create a property mapper - var member = new MemberMapper - { - AutoId = autoId == null ? true : autoId.AutoId, - FieldName = name, - MemberName = memberInfo.Name, - DataType = dataType, - IsEnumerable = isEnumerable, - UnderlyingType = isEnumerable ? Reflection.GetListItemType(dataType) : dataType, - Getter = getter, - Setter = setter - }; - - // check if property has [BsonRef] - var dbRef = (BsonRefAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, dbrefAttr, false) - .FirstOrDefault(); - - if (dbRef != null && memberInfo is PropertyInfo) - { - BsonMapper.RegisterDbRef(this, member, _typeNameBinder, - dbRef.Collection ?? this.ResolveCollectionName((memberInfo as PropertyInfo).PropertyType)); - } - - // support callback to user modify member mapper - this.ResolveMember?.Invoke(mapper.ForType, memberInfo, member); - - // test if has name and there is no duplicate field - // when member is not ignore - if (member.FieldName != null && - mapper.Members.Any(x => x.FieldName.Equals(name, StringComparison.OrdinalIgnoreCase)) == false && - !member.IsIgnore) - { - mapper.Members.Add(member); - } - } - } - - /// - /// Gets MemberInfo that refers to Id from a document object. - /// - protected virtual MemberInfo GetIdMember(IEnumerable members) - { - return Reflection.SelectMember(members, - x => CustomAttributeExtensions.IsDefined(x, typeof(BsonIdAttribute), true), - x => x.Name.Equals("Id", StringComparison.OrdinalIgnoreCase), - x => x.Name.Equals(x.DeclaringType.Name + "Id", StringComparison.OrdinalIgnoreCase)); - } - - /// - /// Returns all member that will be have mapper between POCO class to document - /// - protected virtual IEnumerable GetTypeMembers(Type type) - { - var members = new List(); - - var flags = this.IncludeNonPublic - ? (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) - : (BindingFlags.Public | BindingFlags.Instance); - - members.AddRange(type.GetProperties(flags) - .Where(x => x.CanRead && x.GetIndexParameters().Length == 0) - .Select(x => x as MemberInfo)); - - var shouldIncludeFields = members.Count == 0 - && type.GetTypeInfo().IsValueType; - - if (shouldIncludeFields || this.IncludeFields) - { - members.AddRange(type.GetFields(flags).Where(x => !x.Name.EndsWith("k__BackingField") && x.IsStatic == false) - .Select(x => x as MemberInfo)); - } - - return members; - } - - /// - /// Get best construtor to use to initialize this entity. - /// - Look if contains [BsonCtor] attribute - /// - Look for parameterless ctor - /// - Look for first contructor with parameter and use BsonDocument to send RawValue - /// - protected virtual CreateObject GetTypeCtor(EntityMapper mapper) - { - Type type = mapper.ForType; - List Mappings = new List(); - bool returnZeroParamNull = false; - foreach (ConstructorInfo ctor in type.GetConstructors()) - { - ParameterInfo[] pars = ctor.GetParameters(); - // For 0 parameters, we can let the Reflection.CreateInstance handle it, unless they've specified a [BsonCtor] attribute on a different constructor. - if (pars.Length == 0) - { - returnZeroParamNull = true; - continue; - } - - KeyValuePair[] paramMap = new KeyValuePair[pars.Length]; - int i; - for (i = 0; i < pars.Length; i++) - { - ParameterInfo par = pars[i]; - MemberMapper mi = null; - foreach (MemberMapper member in mapper.Members) - { - if (member.MemberName.ToLower() == par.Name.ToLower() && member.DataType == par.ParameterType) - { - mi = member; - break; - } - } - - if (mi == null) - { - break; - } - - paramMap[i] = new KeyValuePair(mi.FieldName, mi.DataType); - } - - if (i < pars.Length) - { - continue; - } - - CreateObject toAdd = (BsonDocument value) => - Activator.CreateInstance(type, paramMap.Select(x => - this.Deserialize(x.Value, value[x.Key])).ToArray()); - if (ctor.GetCustomAttribute() != null) - { - return toAdd; - } - else - { - Mappings.Add(toAdd); - } - } - - if (returnZeroParamNull) - { - return null; - } - - return Mappings.FirstOrDefault(); - } +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +#if NET8_0_OR_GREATER +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +#endif +using System.Linq; +using System.Reflection; +using System.Threading; + +namespace LiteDB; + +public partial class BsonMapper +{ + /// + /// Mapping cache between Class/BsonDocument + /// + private readonly ConcurrentDictionary _entities = new(); + + /// + /// Get property mapper between typed .NET class and BsonDocument - Cache results + /// + internal EntityMapper GetEntityMapper(Type type) + { + if (_entities.TryGetValue(type, out EntityMapper mapper)) + { + return mapper; + } + + using var cts = new CancellationTokenSource(); + try + { + // We need to add the empty shell, because ``BuildEntityMapper`` may use this method recursively + var newMapper = new EntityMapper(type, cts.Token); + mapper = _entities.GetOrAdd(type, newMapper); + if (ReferenceEquals(mapper, newMapper)) + { + try + { + this.BuildEntityMapper(mapper); + } + catch (Exception ex) + { + _entities.TryRemove(type, out _); + throw new LiteException(LiteException.MAPPING_ERROR, $"Error in '{type.Name}' mapping: {ex.Message}", ex); + } + } + } + finally + { + // Allow the Mapper to be used for de-/serialization + cts.Cancel(); + } + + return mapper; + } + + /// + /// Use this method to override how your class can be, by default, mapped from entity to Bson document. + /// Returns an EntityMapper from each requested Type + /// + protected void BuildEntityMapper(EntityMapper mapper) + { +#if NET8_0_OR_GREATER + var idAttrs = new List { typeof(BsonIdAttribute), typeof(KeyAttribute) }; + var ignoreAttrs = new List { typeof(BsonIgnoreAttribute), typeof(NotMappedAttribute) }; +#else + // in netstandard2.0 KeyAttribute and NotMappedAttribute are not available without adding extra dependencies + var idAttrs = new List { typeof(BsonIdAttribute) }; + var ignoreAttrs = new List { typeof(BsonIgnoreAttribute) }; +#endif + var fieldAttr = typeof(BsonFieldAttribute); + var dbrefAttr = typeof(BsonRefAttribute); + + var members = this.GetTypeMembers(mapper.ForType); + var id = this.GetIdMember(members); + + foreach (var memberInfo in members) + { + // checks [BsonIgnore] + if (ignoreAttrs.Any(ia => CustomAttributeExtensions.IsDefined(memberInfo, ia, true))) continue; + + // checks field name conversion + var name = this.ResolveFieldName(memberInfo.Name); + + // check if property has [BsonField] + var field = (BsonFieldAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, fieldAttr, true) + .FirstOrDefault(); + + // check if property has [BsonField] with a custom field name + if (field != null && field.Name != null) + { + name = field.Name; + } + + // checks if memberInfo is id field + if (memberInfo == id) + { + name = "_id"; + } + + // create getter/setter function + var getter = Reflection.CreateGenericGetter(mapper.ForType, memberInfo); + var setter = Reflection.CreateGenericSetter(mapper.ForType, memberInfo); + + // check if property has [BsonId] to get with was setted AutoId = true + // BsonIdAttribute takes precedence over KeyAttribute if both are present + bool autoId = true; + var bsonIdAttribute = (BsonIdAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, typeof(BsonIdAttribute), true) + .FirstOrDefault(); + if (bsonIdAttribute != null) + { + autoId = bsonIdAttribute.AutoId; + } +#if NET8_0_OR_GREATER + else + { + var keyAttribute = (KeyAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, typeof(KeyAttribute), true) + .FirstOrDefault(); + if (keyAttribute != null) + { + autoId = false; + } + } +#endif + + // get data type + var dataType = memberInfo is PropertyInfo + ? (memberInfo as PropertyInfo).PropertyType + : (memberInfo as FieldInfo).FieldType; + + // check if datatype is list/array + var isEnumerable = Reflection.IsEnumerable(dataType); + + // create a property mapper + var member = new MemberMapper + { + AutoId = autoId, + FieldName = name, + MemberName = memberInfo.Name, + DataType = dataType, + IsEnumerable = isEnumerable, + UnderlyingType = isEnumerable ? Reflection.GetListItemType(dataType) : dataType, + Getter = getter, + Setter = setter + }; + + // check if property has [BsonRef] + var dbRef = (BsonRefAttribute)CustomAttributeExtensions.GetCustomAttributes(memberInfo, dbrefAttr, false) + .FirstOrDefault(); + + if (dbRef != null && memberInfo is PropertyInfo) + { + BsonMapper.RegisterDbRef(this, member, _typeNameBinder, + dbRef.Collection ?? this.ResolveCollectionName((memberInfo as PropertyInfo).PropertyType)); + } + + // support callback to user modify member mapper + this.ResolveMember?.Invoke(mapper.ForType, memberInfo, member); + + // test if has name and there is no duplicate field + // when member is not ignore + if (member.FieldName != null && + mapper.Members.Any(x => x.FieldName.Equals(name, StringComparison.OrdinalIgnoreCase)) == false && + !member.IsIgnore) + { + mapper.Members.Add(member); + } + } + } + + /// + /// Gets MemberInfo that refers to Id from a document object. + /// + protected virtual MemberInfo GetIdMember(IEnumerable members) + { + // check for [Key] attribute as well in .NET 8 or greater + return Reflection.SelectMember(members, + x => CustomAttributeExtensions.IsDefined(x, typeof(BsonIdAttribute), true), +#if NET8_0_OR_GREATER + x => CustomAttributeExtensions.IsDefined(x, typeof(KeyAttribute), true), +#endif + x => x.Name.Equals("Id", StringComparison.OrdinalIgnoreCase), + x => x.Name.Equals(x.DeclaringType.Name + "Id", StringComparison.OrdinalIgnoreCase)); + } + + /// + /// Returns all member that will be have mapper between POCO class to document + /// + protected virtual IEnumerable GetTypeMembers(Type type) + { + var members = new List(); + + var flags = this.IncludeNonPublic + ? (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + : (BindingFlags.Public | BindingFlags.Instance); + + members.AddRange(type.GetProperties(flags) + .Where(x => x.CanRead && x.GetIndexParameters().Length == 0) + .Select(x => x as MemberInfo)); + + var shouldIncludeFields = members.Count == 0 + && type.GetTypeInfo().IsValueType; + + if (shouldIncludeFields || this.IncludeFields) + { + members.AddRange(type.GetFields(flags).Where(x => !x.Name.EndsWith("k__BackingField") && x.IsStatic == false) + .Select(x => x as MemberInfo)); + } + + return members; + } + + /// + /// Get best construtor to use to initialize this entity. + /// - Look if contains [BsonCtor] attribute + /// - Look for parameterless ctor + /// - Look for first contructor with parameter and use BsonDocument to send RawValue + /// + protected virtual CreateObject GetTypeCtor(EntityMapper mapper) + { + Type type = mapper.ForType; + List Mappings = new List(); + bool returnZeroParamNull = false; + foreach (ConstructorInfo ctor in type.GetConstructors()) + { + ParameterInfo[] pars = ctor.GetParameters(); + // For 0 parameters, we can let the Reflection.CreateInstance handle it, unless they've specified a [BsonCtor] attribute on a different constructor. + if (pars.Length == 0) + { + returnZeroParamNull = true; + continue; + } + + KeyValuePair[] paramMap = new KeyValuePair[pars.Length]; + int i; + for (i = 0; i < pars.Length; i++) + { + ParameterInfo par = pars[i]; + MemberMapper mi = null; + foreach (MemberMapper member in mapper.Members) + { + if (member.MemberName.ToLower() == par.Name.ToLower() && member.DataType == par.ParameterType) + { + mi = member; + break; + } + } + + if (mi == null) + { + break; + } + + paramMap[i] = new KeyValuePair(mi.FieldName, mi.DataType); + } + + if (i < pars.Length) + { + continue; + } + + CreateObject toAdd = (BsonDocument value) => + Activator.CreateInstance(type, paramMap.Select(x => + this.Deserialize(x.Value, value[x.Key])).ToArray()); + if (ctor.GetCustomAttribute() != null) + { + return toAdd; + } + else + { + Mappings.Add(toAdd); + } + } + + if (returnZeroParamNull) + { + return null; + } + + return Mappings.FirstOrDefault(); + } } \ No newline at end of file diff --git a/README.md b/README.md index f3f780e82..5d0fc9b6f 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,10 @@ LiteDB is a small, fast and lightweight .NET NoSQL embedded database. - Install from NuGet: `Install-Package LiteDB` +## New v6 + +* Added support for DataAnnotations attributes ([Key] and [NotMapped]) as aliases for [BsonId] and [BsonIgnore] (for .NET 8+). + ## New v5 - New storage engine