database improvements...

This commit is contained in:
jozsef.b@aycode.com 2023-11-23 22:38:13 +01:00
parent a681bbbaf3
commit a1debfd072
24 changed files with 380 additions and 12 deletions

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

View File

@ -0,0 +1,9 @@
namespace AyCode.Core.Tests;
public abstract class TestModelBase
{
protected TestModelBase()
{
//if (IsProductVersion) throw new Exception("IsProductVersion!!!!!");
}
}

View File

@ -3,23 +3,27 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34221.43
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Core", "AyCode.Core\AyCode.Core.csproj", "{8CCC4969-7306-4747-8A58-80AC5A062EE1}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Core", "AyCode.Core\AyCode.Core.csproj", "{8CCC4969-7306-4747-8A58-80AC5A062EE1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Entities", "AyCode.Entities\AyCode.Entities.csproj", "{A2105535-1397-4307-B61B-E49C983353B9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Entities", "AyCode.Entities\AyCode.Entities.csproj", "{A2105535-1397-4307-B61B-E49C983353B9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Entities.Server", "AyCode.Entities.Server\AyCode.Entities.Server.csproj", "{FB027D80-8949-403B-9A86-8E99F305016E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Entities.Server", "AyCode.Entities.Server\AyCode.Entities.Server.csproj", "{FB027D80-8949-403B-9A86-8E99F305016E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Database", "AyCode.Database\AyCode.Database.csproj", "{CAB60420-9F66-42D9-B67E-8E837DBA1F30}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Database", "AyCode.Database\AyCode.Database.csproj", "{CAB60420-9F66-42D9-B67E-8E837DBA1F30}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Interfaces", "AyCode.Interfaces\AyCode.Interfaces.csproj", "{DC42F79D-EEF0-4F32-8608-230F24C6F22A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Interfaces", "AyCode.Interfaces\AyCode.Interfaces.csproj", "{DC42F79D-EEF0-4F32-8608-230F24C6F22A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Interfaces.Server", "AyCode.Interfaces.Server\AyCode.Interfaces.Server.csproj", "{0B5AC35E-3E71-42DC-B503-80D6D3089F91}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Interfaces.Server", "AyCode.Interfaces.Server\AyCode.Interfaces.Server.csproj", "{0B5AC35E-3E71-42DC-B503-80D6D3089F91}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Core.Server", "AyCode.Core.Server\AyCode.Core.Server.csproj", "{F8ECCA33-B5EA-490D-B1A1-D33B5E4238A5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Core.Server", "AyCode.Core.Server\AyCode.Core.Server.csproj", "{F8ECCA33-B5EA-490D-B1A1-D33B5E4238A5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Utils", "AyCode.Utils\AyCode.Utils.csproj", "{35D47907-CE4F-435B-823E-A02BE59C16D7}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Utils", "AyCode.Utils\AyCode.Utils.csproj", "{35D47907-CE4F-435B-823E-A02BE59C16D7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Utils.Server", "AyCode.Utils.Server\AyCode.Utils.Server.csproj", "{EBC6371C-9454-473D-9547-DF9DECEB2D2A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Utils.Server", "AyCode.Utils.Server\AyCode.Utils.Server.csproj", "{EBC6371C-9454-473D-9547-DF9DECEB2D2A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Database.Tests", "AyCode.Database.Tests\AyCode.Database.Tests.csproj", "{15272F57-771E-47BE-A960-AD75935254D0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Core.Tests", "AyCode.Core.Tests\AyCode.Core.Tests.csproj", "{320A245F-6731-476D-A9D8-77888E6B5D9C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -63,6 +67,14 @@ Global
{EBC6371C-9454-473D-9547-DF9DECEB2D2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBC6371C-9454-473D-9547-DF9DECEB2D2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBC6371C-9454-473D-9547-DF9DECEB2D2A}.Release|Any CPU.Build.0 = Release|Any CPU
{15272F57-771E-47BE-A960-AD75935254D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{15272F57-771E-47BE-A960-AD75935254D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15272F57-771E-47BE-A960-AD75935254D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15272F57-771E-47BE-A960-AD75935254D0}.Release|Any CPU.Build.0 = Release|Any CPU
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.10" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.10" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AyCode.Core.Server\AyCode.Core.Server.csproj" />
<ProjectReference Include="..\AyCode.Core.Tests\AyCode.Core.Tests.csproj" />
<ProjectReference Include="..\AyCode.Core\AyCode.Core.csproj" />
<ProjectReference Include="..\AyCode.Database\AyCode.Database.csproj" />
<ProjectReference Include="..\AyCode.Entities.Server\AyCode.Entities.Server.csproj" />
<ProjectReference Include="..\AyCode.Entities\AyCode.Entities.csproj" />
<ProjectReference Include="..\AyCode.Interfaces.Server\AyCode.Interfaces.Server.csproj" />
<ProjectReference Include="..\AyCode.Interfaces\AyCode.Interfaces.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,12 @@
using AyCode.Core.Tests;
using AyCode.Database.DbContexts;
namespace AyCode.Database.Tests;
public abstract class DatabaseTestModelBase<TDal> : TestModelBase where : DbContextBase
{
protected DatabaseTestModelBase()
{
//var dal = new dal
}
}

View File

@ -0,0 +1,11 @@
namespace AyCode.Database.Tests
{
[TestClass]
public abstract class DatabaseTests : DatabaseTestModelBase
{
[TestMethod]
public void TestMethod1()
{
}
}
}

View File

@ -0,0 +1 @@
global using Microsoft.VisualStudio.TestTools.UnitTesting;

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AyCode.Database.DbContexts;
using AyCode.Utils.Extensions;
namespace AyCode.Database;
public class DalBase<TDbContext> where TDbContext : DbContextBase
{
public string Name { get; private set; }
private TDbContext _ctx;
public TDbContext Ctx => _ctx;
public DalBase() : this(Activator.CreateInstance<TDbContext>())
{ }
public DalBase(TDbContext ctx)
{
_ctx = ctx;
if (_ctx.Name.IsNullOrWhiteSpace())
_ctx.Name = _ctx.GetType().Name;
Name = $"{this.GetType().Name}, {_ctx.Name}";
}
public override string ToString()
{
return Name;
}
}

View File

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
using System.Runtime.CompilerServices;
using Microsoft.EntityFrameworkCore;
using AyCode.Database.Extensions;
using AyCode.Interfaces.TimeStampInfo;
@ -10,12 +11,12 @@ public class DbContextBase : DbContext
public Guid SessionId { get; protected set; } = Guid.NewGuid();
public DbContextBase() : this(string.Empty)
public DbContextBase()
{
//DbInterception.Add(new UtcDateTimeDbCommandInterceptor());
}
public DbContextBase(string name) : base()
public DbContextBase(string name) : this()
{
Name = name;
}

View File

@ -6,4 +6,8 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AyCode.Utils\AyCode.Utils.csproj" />
</ItemGroup>
</Project>

View File

@ -6,4 +6,8 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AyCode.Interfaces\AyCode.Interfaces.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,10 @@
using AyCode.Entities.Interfaces;
using AyCode.Interfaces;
using AyCode.Interfaces.TimeStampInfo;
namespace AyCode.Entities.Profiles;
public interface IProfileBase : IEntityGuid, IOwnerId, ITimeStampInfo
{
Guid UserMediaId { get; set; }
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AyCode.Entities.Profiles
{
[Table("ProfileBase")]
public class ProfileBase : IProfileBase
{
public ProfileBase() { }
public ProfileBase(Guid ownerId) : this()
{
OwnerId = ownerId;
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public Guid OwnerId { get; }
public Guid UserMediaId { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using AyCode.Entities.Interfaces;
using AyCode.Interfaces.TimeStampInfo;
namespace AyCode.Entities.Users;
public interface IUserBase : IEntityGuid, ITimeStampInfo
{
string Email { get; }
string Password { get; }
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AyCode.Entities.Users
{
[Table("ProfileBase")]
public class UserBase : IUserBase
{
public UserBase() { }
public UserBase(string email, string password) : this(Guid.NewGuid(), email, password) { }
public UserBase(Guid id, string email, string password) : this()
{
Id = id;
Email = email;
Password = password;
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public string Email { get; }
public string Password { get; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
}
}

View File

@ -0,0 +1,6 @@
namespace AyCode.Interfaces;
public interface IOwnerId
{
Guid OwnerId { get; }
}

View File

@ -6,4 +6,8 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,20 @@
using JetBrains.Annotations;
namespace AyCode.Utils.Extensions
{
public static class DateTimeExtension
{
public static bool IsNullOrEmpty(this DateTime dateTime) => dateTime == DateTime.MinValue;
[ContractAnnotation("dateTime:null => true; dateTime:notnull <= false")]
public static bool IsNullOrEmpty(this DateTime? dateTime) => dateTime == null || dateTime == DateTime.MinValue;
public static bool IsEqualSqlDateTime2(this DateTime dtSource, DateTime dateTime)
{
return dtSource == dateTime ||
(dtSource.Kind == dateTime.Kind &&
dtSource.Millisecond == dateTime.Millisecond && dtSource.Hour == dateTime.Hour && dtSource.Second == dateTime.Second && dtSource.Minute == dateTime.Minute &&
dtSource.Day == dateTime.Day && dtSource.Month == dateTime.Month && dtSource.Year == dateTime.Year);
}
}
}

View File

@ -0,0 +1,15 @@
using JetBrains.Annotations;
namespace AyCode.Utils.Extensions
{
public static class GuidExtensions
{
//[ContractAnnotation("=> true, result: notnull; => false, result: null")]
//[ContractAnnotation("true => null; false => notnull")]
public static bool IsNullOrEmpty(this Guid guid) => guid == Guid.Empty;
//[ContractAnnotation("=> true, result: notnull; => false, result: null")]
[ContractAnnotation("guid:null => true; guid:notnull <= false")]
public static bool IsNullOrEmpty(this Guid? guid) => guid == null || guid == Guid.Empty;
}
}

View File

@ -0,0 +1,28 @@
using AyCode.Utils.Wrappers;
namespace AyCode.Utils.Extensions
{
public static class LockExtensions
{
public static IDisposable UseWaitOne(this Mutex mutex)
{
mutex.WaitOne();
return new ReleaseWrapperMutex(mutex);
}
public static IDisposable UseWait(this SemaphoreSlim semaphore, CancellationToken cancelToken = default)
{
semaphore.Wait(cancelToken);
return new ReleaseWrapperSemaphore(semaphore);
}
public static async Task<IDisposable> UseWaitAsync(this SemaphoreSlim semaphore, CancellationToken cancelToken = default)
{
await semaphore.WaitAsync(cancelToken).ConfigureAwait(false);
return new ReleaseWrapperSemaphore(semaphore);
}
}
}

View File

@ -0,0 +1,40 @@
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
namespace AyCode.Utils.Extensions
{
public static class StringExtensions
{
//[ContractAnnotation("str:null => true; str:notnull <= false")]
[ContractAnnotation("str:null => true; str:notnull <= false")]
public static bool IsNullOrEmpty([NotNullWhen(returnValue: false)] this string str) => str == null || str.Length == 0;
[ContractAnnotation("str:null => true;")]
public static bool IsNullOrWhiteSpace([NotNullWhen(returnValue: false)] this string str)
{
if (str == null || str.Length == 0) return true;
if (!char.IsWhiteSpace(str[0])) return false;
for (var i = 1; i < str.Length; i++)
{
if (!char.IsWhiteSpace(str[i]))
return false;
}
return true;
}
public static string FirstLetterToUpper(string str)
{
if (str.IsNullOrWhiteSpace())
return str;
if (str.Length == 1)
return str.ToUpper();
str = str.ToLower();
return char.ToUpper(str[0]) + str[1..];
}
}
}

View File

@ -0,0 +1,19 @@
namespace AyCode.Utils.Wrappers
{
public class ReleaseWrapperMutex : IDisposable
{
private readonly Mutex _mutex;
private bool _isDisposed;
public ReleaseWrapperMutex(Mutex mutex) => _mutex = mutex;
public void Dispose()
{
if (_isDisposed)
return;
_mutex.ReleaseMutex();
_isDisposed = true;
}
}
}

View File

@ -0,0 +1,19 @@
namespace AyCode.Utils.Wrappers
{
public class ReleaseWrapperSemaphore : IDisposable
{
private readonly SemaphoreSlim _semaphore;
private bool _isDisposed;
public ReleaseWrapperSemaphore(SemaphoreSlim semaphore) => _semaphore = semaphore;
public void Dispose()
{
if (_isDisposed)
return;
_semaphore.Release();
_isDisposed = true;
}
}
}