From d070050bc97bd0a8a08b23c782861a65738b913d Mon Sep 17 00:00:00 2001 From: Ivan Novikov Date: Fri, 19 Jan 2024 02:57:37 +0300 Subject: [PATCH] Upgrade to net8.0 --- Slant.Entity.Demo/Slant.Entity.Demo.csproj | 4 +- Slant.Entity.Tests/DbContextScopeTests.cs | 6 +- .../Helpers/ObjectIdGenerator.cs | 162 ++++++++++++++++++ .../SqliteMemoryDatabaseLifetimeManager.cs | 2 +- Slant.Entity.Tests/Slant.Entity.Tests.csproj | 6 +- Slant.Entity/Slant.Entity.csproj | 12 +- 6 files changed, 177 insertions(+), 15 deletions(-) create mode 100644 Slant.Entity.Tests/Helpers/ObjectIdGenerator.cs diff --git a/Slant.Entity.Demo/Slant.Entity.Demo.csproj b/Slant.Entity.Demo/Slant.Entity.Demo.csproj index 020ac62..42c3bb5 100644 --- a/Slant.Entity.Demo/Slant.Entity.Demo.csproj +++ b/Slant.Entity.Demo/Slant.Entity.Demo.csproj @@ -2,12 +2,12 @@ Exe - net7.0 + net8.0 warnings - + diff --git a/Slant.Entity.Tests/DbContextScopeTests.cs b/Slant.Entity.Tests/DbContextScopeTests.cs index fba630a..c1aa853 100644 --- a/Slant.Entity.Tests/DbContextScopeTests.cs +++ b/Slant.Entity.Tests/DbContextScopeTests.cs @@ -9,7 +9,7 @@ using System.Runtime.Serialization; using System.Threading.Tasks; using Xunit; - +using ObjectIDGenerator = Slant.Entity.Tests.Helpers.ObjectIDGenerator; namespace Slant.Entity.Tests; public sealed class DbContextScopeTests : IDisposable @@ -448,7 +448,7 @@ public void Multiple_threads_which_create_a_DbContextScope_use_separate_DbContex lock (lockObject) { - var dbContextScopeId = idGenerator.GetId(dbContextScope, out bool _); + var dbContextScopeId = idGenerator.GetId(dbContextScope); dbContextScopeIds.Add(dbContextScopeId); } @@ -457,7 +457,7 @@ public void Multiple_threads_which_create_a_DbContextScope_use_separate_DbContex lock (lockObject) { - var dbContextId = idGenerator.GetId(dbContext, out bool _); + var dbContextId = idGenerator.GetId(dbContext); dbContextIds.Add(dbContextId); } }); diff --git a/Slant.Entity.Tests/Helpers/ObjectIdGenerator.cs b/Slant.Entity.Tests/Helpers/ObjectIdGenerator.cs new file mode 100644 index 0000000..6df394c --- /dev/null +++ b/Slant.Entity.Tests/Helpers/ObjectIdGenerator.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; + +namespace Slant.Entity.Tests.Helpers; + +/// +/// A class that acts like a dictionary with weakref'ed keys, meaning, +/// the entry will be removed once its key is garbage-collected. +/// required by ObjectIDGenerator +/// +internal class WeakKeyDict +{ + private struct Pair + { + private readonly WeakReference _wkey; + public TValue val; + + public Pair(TKey k, TValue v) + { + _wkey = new WeakReference(k); + val = v; + } + + public bool IsAlive() + { + return _wkey.IsAlive; + } + public bool IsEqual(TKey key) + { + return _wkey.Target != null && _wkey.Target.Equals(key); + } + } + + private Dictionary> dict; + + public WeakKeyDict() : this(8000) + { + } + public WeakKeyDict(int capacity) + { + dict = new Dictionary>(capacity); + } + + public void Add(TKey key, TValue val) + { + int hash = key!.GetHashCode(); + if (!dict.ContainsKey(hash)) + { + var buckets = new List(); + buckets.Add(new Pair(key, val)); + dict.Add(hash, buckets); + } + else + { + var buckets = dict[hash]; + bool found = false; + for (int i = buckets.Count - 1; i >= 0; i--) + { + Pair p = buckets[i]; + if (!p.IsAlive()) + { + buckets.RemoveAt(i); + } + else if (p.IsEqual(key)) + { + found = true; + p.val = val; + } + } + if (!found) + { + buckets.Add(new Pair(key, val)); + } + } + } + + public bool TryGetValue(TKey key, out TValue val) + { + int hash = key.GetHashCode(); + List buckets; + if (dict.TryGetValue(hash, out buckets)) + { + for (int i = buckets.Count - 1; i >= 0; i--) + { + Pair p = buckets[i]; + if (!p.IsAlive()) + { + buckets.RemoveAt(i); + } + else if (p.IsEqual(key)) + { + val = p.val; + return true; + } + } + } + val = default(TValue); + return false; + } + + public void Compact() + { + var deadKeys = new List(); + foreach (KeyValuePair> item in dict) + { + for (int i = item.Value.Count - 1; i >= 0; i--) + { + Pair p = item.Value[i]; + if (!p.IsAlive()) + { + item.Value.RemoveAt(i); + } + } + if (item.Value.Count < 1) + { + deadKeys.Add(item.Key); + } + } + foreach (int k in deadKeys) + { + dict.Remove(k); + } + } +} + +/// +/// a class that generates a unique identifier for every object +/// +internal sealed class ObjectIDGenerator +{ + private readonly WeakKeyDict _dict; + private long _counter; + + public ObjectIDGenerator() + { + _dict = new WeakKeyDict(); + _counter = 0; + } + + public long GetId(object obj) + { + long id; + lock (this) + { + if (_dict.TryGetValue(obj, out id)) + { + return id; + } + else + { + _counter += 1; + _dict.Add(obj, _counter); + return _counter; + } + } + } + + public void Compact() + { + _dict.Compact(); + } +} \ No newline at end of file diff --git a/Slant.Entity.Tests/Helpers/SqliteMemoryDatabaseLifetimeManager.cs b/Slant.Entity.Tests/Helpers/SqliteMemoryDatabaseLifetimeManager.cs index c0e7909..6f56b81 100644 --- a/Slant.Entity.Tests/Helpers/SqliteMemoryDatabaseLifetimeManager.cs +++ b/Slant.Entity.Tests/Helpers/SqliteMemoryDatabaseLifetimeManager.cs @@ -8,7 +8,7 @@ internal class SqliteMemoryDatabaseLifetimeManager : IDisposable { public readonly string ConnectionString = $"DataSource={Guid.NewGuid()};mode=memory;cache=shared"; - private DbConnection? _keepAliveConnection; + private DbConnection _keepAliveConnection; public SqliteMemoryDatabaseLifetimeManager() { diff --git a/Slant.Entity.Tests/Slant.Entity.Tests.csproj b/Slant.Entity.Tests/Slant.Entity.Tests.csproj index 6bd53b4..4d38fee 100644 --- a/Slant.Entity.Tests/Slant.Entity.Tests.csproj +++ b/Slant.Entity.Tests/Slant.Entity.Tests.csproj @@ -1,14 +1,14 @@ - net6.0;net7.0 - enable + net8.0 + disable false - + diff --git a/Slant.Entity/Slant.Entity.csproj b/Slant.Entity/Slant.Entity.csproj index 07a09dc..ff25405 100644 --- a/Slant.Entity/Slant.Entity.csproj +++ b/Slant.Entity/Slant.Entity.csproj @@ -1,10 +1,10 @@ - + - net6.0 + net8.0 enable Slant.Entity - 7.0.12 + 8.0.1 Mehdi El Gueddari;Ivan Novikov DbContextScope;DbContext;EF;EFCore;EntityFramework;EntityFrameworkCore;UnitOfWork;AmbientDbContext;AmbientContext;RepositoryPattern A library for managing the lifetime of Entity Framework Core DbContext instances. This package is based on the original DbContextScope repository by Mehdi El Gueddari, updated for .NET 6+ and EF Core, with a number of additional improvements and bug fixes. @@ -24,9 +24,9 @@ - - - + + +