diff --git a/sample/Tenant.Api.Contracts/DDD/Domain/Consts/TenantConnectionStringConsts.cs b/sample/Tenant.Api.Contracts/DDD/Domain/Consts/TenantConnectionStringConsts.cs new file mode 100644 index 0000000..cff4313 --- /dev/null +++ b/sample/Tenant.Api.Contracts/DDD/Domain/Consts/TenantConnectionStringConsts.cs @@ -0,0 +1,14 @@ +namespace Tenant.Api.DDD.Domain.Consts; + +public static class TenantConnectionStringConsts +{ + /// + /// Default value: 64 + /// + public static int MaxNameLength { get; set; } = 64; + + /// + /// Default value: 1024 + /// + public static int MaxValueLength { get; set; } = 1024; +} diff --git a/sample/Tenant.Api.Contracts/DDD/Domain/Consts/TenantConsts.cs b/sample/Tenant.Api.Contracts/DDD/Domain/Consts/TenantConsts.cs new file mode 100644 index 0000000..b209623 --- /dev/null +++ b/sample/Tenant.Api.Contracts/DDD/Domain/Consts/TenantConsts.cs @@ -0,0 +1,9 @@ +namespace Tenant.Api.DDD.Domain.Consts; + +public static class TenantConsts +{ + /// + /// Default value: 64 + /// + public static int MaxNameLength { get; set; } = 64; +} diff --git a/sample/Tenant.Api.Contracts/DDD/Domain/Shared/TenantEto.cs b/sample/Tenant.Api.Contracts/DDD/Domain/Shared/TenantEto.cs new file mode 100644 index 0000000..6d166bd --- /dev/null +++ b/sample/Tenant.Api.Contracts/DDD/Domain/Shared/TenantEto.cs @@ -0,0 +1,11 @@ +using System; + +namespace Tenant.Api.DDD.Domain.Shared; + +[Serializable] +public class TenantEto +{ + public Guid Id { get; set; } + + public string Name { get; set; } +} diff --git a/sample/Tenant.Api.Contracts/Tenant.Api.Contracts.csproj b/sample/Tenant.Api.Contracts/Tenant.Api.Contracts.csproj new file mode 100644 index 0000000..c1179db --- /dev/null +++ b/sample/Tenant.Api.Contracts/Tenant.Api.Contracts.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/sample/Tenant.Api/DDD/Application/TenantAppService.cs b/sample/Tenant.Api/DDD/Application/TenantAppService.cs new file mode 100644 index 0000000..8b43f6e --- /dev/null +++ b/sample/Tenant.Api/DDD/Application/TenantAppService.cs @@ -0,0 +1,7 @@ +using Easy.DDD.Application; + +namespace Tenant.Api.DDD.Application; + +public class TenantAppService : IApiService +{ +} diff --git a/sample/Tenant.Api/DDD/Domain/TenantAggregation/ITenantManager.cs b/sample/Tenant.Api/DDD/Domain/TenantAggregation/ITenantManager.cs new file mode 100644 index 0000000..fd87f75 --- /dev/null +++ b/sample/Tenant.Api/DDD/Domain/TenantAggregation/ITenantManager.cs @@ -0,0 +1,8 @@ +namespace Tenant.Api.DDD.Domain.TenantAggregate; + +public interface ITenantManager +{ + Task CreateAsync(string name); + + Task ChangeNameAsync(Tenant tenant, string name); +} diff --git a/sample/Tenant.Api/DDD/Domain/TenantAggregation/Tenant.cs b/sample/Tenant.Api/DDD/Domain/TenantAggregation/Tenant.cs new file mode 100644 index 0000000..4e72417 --- /dev/null +++ b/sample/Tenant.Api/DDD/Domain/TenantAggregation/Tenant.cs @@ -0,0 +1,56 @@ +using Easy; +using Easy.DDD.Domain.Entities; +using Tenant.Api.DDD.Domain.Consts; + +namespace Tenant.Api.DDD.Domain.TenantAggregation; + +public class Tenant : AggregateRoot +{ + public virtual string Name { get; protected set; } + + public virtual List ConnectionStrings { get; protected set; } + + protected Tenant() + { + + } + + protected internal Tenant(Guid id, string name) + : base(id) + { + SetName(name); + + ConnectionStrings = new List(); + } + + + public virtual void SetConnectionString(string name, string connectionString) + { + var tenantConnectionString = ConnectionStrings.FirstOrDefault(x => x.Name == name); + + if (tenantConnectionString != null) + { + tenantConnectionString.SetValue(connectionString); + } + else + { + ConnectionStrings.Add(new TenantConnectionString(Id, name, connectionString)); + } + } + + + public virtual void RemoveConnectionString(string name) + { + var tenantConnectionString = ConnectionStrings.FirstOrDefault(x => x.Name == name); + + if (tenantConnectionString != null) + { + ConnectionStrings.Remove(tenantConnectionString); + } + } + + protected internal virtual void SetName(string name) + { + Name = Check.NotNullOrWhiteSpace(name, nameof(name), TenantConsts.MaxNameLength); + } +} diff --git a/sample/Tenant.Api/DDD/Domain/TenantAggregation/TenantConnectionString.cs b/sample/Tenant.Api/DDD/Domain/TenantAggregation/TenantConnectionString.cs new file mode 100644 index 0000000..9eeea0d --- /dev/null +++ b/sample/Tenant.Api/DDD/Domain/TenantAggregation/TenantConnectionString.cs @@ -0,0 +1,36 @@ +using Easy; +using Easy.DDD.Domain.Entities; +using Tenant.Api.DDD.Domain.Consts; + +namespace Tenant.Api.DDD.Domain.TenantAggregation; + +public class TenantConnectionString : Entity +{ + public virtual Guid TenantId { get; protected set; } + + public virtual string Name { get; protected set; } + + public virtual string Value { get; protected set; } + + protected TenantConnectionString() + { + + } + + public TenantConnectionString(Guid tenantId, string name, string value) + { + TenantId = tenantId; + Name = Check.NotNullOrWhiteSpace(name, nameof(name), TenantConnectionStringConsts.MaxNameLength); + SetValue(value); + } + + public virtual void SetValue(string value) + { + Value = Check.NotNullOrWhiteSpace(value, nameof(value), TenantConnectionStringConsts.MaxValueLength); + } + + public override object[] GetKeys() + { + return new object[] { TenantId, Name }; + } +} diff --git a/sample/Tenant.Api/DDD/Domain/TenantAggregation/TenantManager.cs b/sample/Tenant.Api/DDD/Domain/TenantAggregation/TenantManager.cs new file mode 100644 index 0000000..9af193b --- /dev/null +++ b/sample/Tenant.Api/DDD/Domain/TenantAggregation/TenantManager.cs @@ -0,0 +1,44 @@ +using Easy; +using Easy.DDD.Domain.Repositories; +using Easy.Guids; +using Microsoft.EntityFrameworkCore; + +namespace Tenant.Api.DDD.Domain.TenantAggregation; + +public class TenantManager +{ + public IRepository TenantRepository { get; } + protected IGuidGenerator GuidGenerator { get; } + public TenantManager(IRepository tenantRepository) + { + TenantRepository = tenantRepository; + } + public virtual async Task CreateAsync(string name) + { + Check.NotNull(name, nameof(name)); + + await ValidateNameAsync(name); + return new Tenant(GuidGenerator.Create(), name); + } + + public virtual async Task ChangeNameAsync(Tenant tenant, string name) + { + Check.NotNull(tenant, nameof(tenant)); + Check.NotNull(name, nameof(name)); + + await ValidateNameAsync(name, tenant.Id); + tenant.SetName(name); + } + + protected virtual async Task ValidateNameAsync(string name, Guid? expectedId = null) + { + var tenant = await TenantRepository + .Where(o => o.Name == name) + .Include(x => x.ConnectionStrings) + .OrderBy(t => t.Id) + .FirstOrDefaultAsync(); + + When.Is(tenant != null && tenant.Id != expectedId, "重复的租户名称: " + name); + + } +} diff --git a/sample/Tenant.Api/TenantMappingProfile.cs b/sample/Tenant.Api/TenantMappingProfile.cs new file mode 100644 index 0000000..e0a4d8d --- /dev/null +++ b/sample/Tenant.Api/TenantMappingProfile.cs @@ -0,0 +1,13 @@ +using AutoMapper; +using Tenant.Api.DDD.Domain.Shared; + +namespace Tenant.Api.DDD.Domain; + +public class TenantMappingProfile : Profile +{ + public TenantMappingProfile() + { + + CreateMap(); + } +}