Infrastructure

This commit is contained in:
2026-04-22 20:51:02 +04:30
parent c64c3dd9be
commit 64ee78e320
199 changed files with 7428 additions and 1027 deletions
@@ -0,0 +1,89 @@
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
using Vizhvizh.BuildingBlocks.Domain;
public class BaseEntityConfiguration<T, TId, TIdType> : IEntityTypeConfiguration<T>
where T : Entity<TId>
where TId : TypedIdValueBase<TIdType>
{
public virtual void Configure(EntityTypeBuilder<T> builder)
{
// تنظیمات Id
ConfigureId(builder);
// تنظیمات RowVersion
ConfigureRowVersion(builder);
// تنظیمات CreateOn (اگر وجود داشته باشد)
ConfigureCreateOn(builder);
}
private void ConfigureId(EntityTypeBuilder<T> builder)
{
builder.HasKey(x => x.Id);
if (typeof(TIdType) == typeof(int) || typeof(TIdType) == typeof(long))
{
// ❌ مشکل: اینجا نمی‌توانیم به نام جدول دسترسی داشته باشیم
// builder.UseHiLo($"Sequence_{typeof(T).Name}")
// ✅ راه‌حل: در اینجا فقط تنظیمات Id را انجام بده، Hi-Lo را بعداً اعمال کن
builder.Property(x => x.Id)
.HasConversion(
id => id.Value,
value => (TId)Activator.CreateInstance(typeof(TId), value)!)
.ValueGeneratedOnAdd();
// ❌ UseHiLo را اینجا نزنید، چون هنوز نام جدول مشخص نیست
}
else if (typeof(TIdType) == typeof(Guid))
{
builder.Property(x => x.Id)
.HasConversion(
id => id.Value,
value => (TId)Activator.CreateInstance(typeof(TId), value)!)
.HasDefaultValueSql("NEWSEQUENTIALID()")
.ValueGeneratedOnAdd();
}
else if (typeof(TIdType) == typeof(string))
{
builder.Property(x => x.Id)
.HasConversion(
id => id.Value,
value => (TId)Activator.CreateInstance(typeof(TId), value)!)
.HasMaxLength(50);
}
}
private void ConfigureRowVersion(EntityTypeBuilder<T> builder)
{
// بررسی وجود خاصیت RowVersion با Reflection
var hasRowVersion = typeof(T).GetProperty("RowVersion") != null;
if (hasRowVersion)
{
// تنظیم RowVersion به عنوان Concurrency Token
builder.Property<byte[]>("RowVersion")
.IsRowVersion() // این یک خط همه کارها را می‌کند
.IsConcurrencyToken()
.ValueGeneratedOnAddOrUpdate();
// برای دیتابیس‌های مختلف:
// builder.Property<byte[]>("RowVersion").HasDefaultValueSql("rowversion");
}
}
private void ConfigureCreateOn(EntityTypeBuilder<T> builder)
{
// تنظیم CreateOn (اگر وجود داشته باشد)
var hasCreateOn = typeof(T).GetProperty("CreateOn") != null;
if (hasCreateOn)
{
builder.Property<DateTime>("CreateOn")
.HasDefaultValueSql("GETDATE()") // SQL Server
// برای PostgreSQL: .HasDefaultValueSql("CURRENT_TIMESTAMP")
// برای MySQL: .HasDefaultValueSql("CURRENT_TIMESTAMP")
.ValueGeneratedOnAdd();
}
}
}
@@ -0,0 +1,5 @@
namespace Vizhvizh.BuildingBlocks.Infrastructure.Lifetimes;
public interface IScopeDependency
{
}
@@ -0,0 +1,5 @@
namespace Vizhvizh.BuildingBlocks.Infrastructure.Lifetimes;
public interface ISingletonDependency
{
}
@@ -0,0 +1,5 @@
namespace Vizhvizh.BuildingBlocks.Infrastructure.Lifetimes;
public interface ITransientDependency
{
}
@@ -0,0 +1,117 @@
using Microsoft.EntityFrameworkCore;
using Vizhvizh.BuildingBlocks.Domain;
public static class ModelBuilderExtensions
{
public static void AddHiLoSequences(this ModelBuilder modelBuilder)
{
var entityTypes = modelBuilder.Model.GetEntityTypes();
foreach (var entityType in entityTypes)
{
var primaryKey = entityType.FindPrimaryKey();
if (primaryKey == null) continue;
var keyProperty = primaryKey.Properties.FirstOrDefault();
if (keyProperty == null) continue;
// ✅ استخراج نوع واقعی از TypedIdValueBase
var actualKeyType = GetUnderlyingKeyType(keyProperty.ClrType);
// فقط برای int و long
if (actualKeyType == typeof(int) || actualKeyType == typeof(long))
{
var tableName = entityType.GetTableName();
var sequenceName = GetSequenceName(tableName ?? entityType.Name);
var schema = entityType.GetSchema();
if (actualKeyType == typeof(int))
{
modelBuilder.HasSequence<int>(sequenceName, schema)
.StartsAt(1)
.IncrementsBy(1);
}
else if (actualKeyType == typeof(long))
{
modelBuilder.HasSequence<long>(sequenceName, schema)
.StartsAt(1)
.IncrementsBy(1);
}
keyProperty.SetHiLoSequenceName(sequenceName);
}
}
}
//public static void UseHiLoForEntities(this ModelBuilder modelBuilder)
//{
// var entityTypes = modelBuilder.Model.GetEntityTypes();
// foreach (var entityType in entityTypes)
// {
// var primaryKey = entityType.FindPrimaryKey();
// if (primaryKey == null) continue;
// var keyProperty = primaryKey.Properties.FirstOrDefault();
// if (keyProperty == null) continue;
// // ✅ از همان متد استفاده کنید
// var actualKeyType = GetUnderlyingKeyType(keyProperty.ClrType);
// if (actualKeyType == typeof(int) || actualKeyType == typeof(long))
// {
// var tableName = entityType.GetTableName();
// var sequenceName = GetSequenceName(tableName ?? entityType.Name);
// // تنظیم Hi-Lo روی Property
// keyProperty.SetHiLoSequenceName(sequenceName);
// }
// }
//}
/// <summary>
/// استخراج نوع اصلی از TypedIdValueBase
/// پشتیبانی از:
/// - TypedIdValueBase<int>
/// - TypedIdValueBase<long>
/// - CategoryId : TypedIdValueBase<long>
/// </summary>
private static Type GetUnderlyingKeyType(Type keyType)
{
// حالت 1: خود keyType از نوع TypedIdValueBase<T> باشد
if (keyType.IsGenericType &&
keyType.GetGenericTypeDefinition() == typeof(TypedIdValueBase<>))
{
return keyType.GetGenericArguments()[0];
}
// حالت 2: keyType از TypedIdValueBase<T> ارث‌بری کرده باشد
var baseType = keyType.BaseType;
while (baseType != null && baseType != typeof(object))
{
if (baseType.IsGenericType &&
baseType.GetGenericTypeDefinition() == typeof(TypedIdValueBase<>))
{
return baseType.GetGenericArguments()[0];
}
baseType = baseType.BaseType;
}
// حالت 3: خود keyType int یا long باشد
if (keyType == typeof(int) || keyType == typeof(long) ||
keyType == typeof(int?) || keyType == typeof(long?))
{
return Nullable.GetUnderlyingType(keyType) ?? keyType;
}
// حالت 4: نوع دیگر (مثلاً Guid, string)
return keyType;
}
private static string GetSequenceName(string tableName)
{
return $"Sequence_{tableName}";
}
}
@@ -6,14 +6,7 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.25" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.25" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.25" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Scrutor" Version="6.1.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VichVich.BuildingBlocks.Application\Vizhvizh.BuildingBlocks.Application.csproj" />