ИНН и описание

This commit is contained in:
Халимов Рустам
2026-02-16 00:06:10 +03:00
parent abe0ccb390
commit 3524e0d0af
16 changed files with 659 additions and 19 deletions

View File

@@ -41,6 +41,16 @@ public record RegisterUserCommand : IRequest<Guid>
/// </summary>
public string? CompanyName { get; init; }
/// <summary>
/// ИНН (необязательно).
/// </summary>
public string? Inn { get; init; }
/// <summary>
/// Описание исполнителя или компании (необязательно, максимум 2048 символов).
/// </summary>
public string? Description { get; init; }
/// <summary>
/// Роль (по умолчанию User).
/// </summary>
@@ -68,26 +78,28 @@ public class RegisterUserCommandHandler : IRequestHandler<RegisterUserCommand, G
var passwordHash = _passwordHasher.HashPassword(request.Password);
var account = Account.Create(request.Phone, passwordHash);
// Добавляем роль, если она отличается от User
if (request.Role != Role.User && request.Role != Role.Admin)
if (request.Role != Role.User && request.Role != Role.Admin)
{
// Здесь можно добавить логику проверки прав, но для MVP разрешим
account.Roles.Add(request.Role);
}
var profile = UserProfile.Create(
account.Id,
request.FirstName,
request.LastName,
request.Patronymic,
request.CompanyName);
account.Id,
request.FirstName,
request.LastName,
request.Patronymic,
request.CompanyName,
request.Inn,
request.Description);
account.SetProfile(profile);
await _accountRepository.AddAsync(account, cancellationToken);
// Предполагаем, что AccountRepository.AddAsync сохранит всё дерево сущностей
return account.Id;
}
}

View File

@@ -10,6 +10,8 @@ public record UpdateProfileCommand : IRequest
public string LastName { get; init; } = default!;
public string? Patronymic { get; init; }
public string? CompanyName { get; init; }
public string? Inn { get; init; }
public string? Description { get; init; }
}
public class UpdateProfileCommandHandler : IRequestHandler<UpdateProfileCommand>
@@ -46,7 +48,9 @@ public class UpdateProfileCommandHandler : IRequestHandler<UpdateProfileCommand>
request.FirstName,
request.LastName,
request.Patronymic,
request.CompanyName);
request.CompanyName,
request.Inn,
request.Description);
await _accountRepository.UpdateAsync(account, cancellationToken);
}

View File

@@ -7,13 +7,15 @@ namespace Nashel.Modules.Identity.Application.Queries.GetProfile;
public record GetProfileQuery : IRequest<ProfileResponse>;
public record ProfileResponse(
Guid Id,
string Phone,
Guid Id,
string Phone,
List<string> Roles,
string FirstName,
string LastName,
string? Patronymic,
string? CompanyName,
string? Inn,
string? Description,
string FullName,
string? AvatarUrl,
List<string> Competencies);
@@ -50,13 +52,15 @@ public class GetProfileQueryHandler : IRequestHandler<GetProfileQuery, ProfileRe
}
return new ProfileResponse(
account.Id,
account.Phone,
account.Id,
account.Phone,
account.Roles.Select(r => r.ToString()).ToList(),
account.Profile.FirstName,
account.Profile.LastName,
account.Profile.Patronymic,
account.Profile.CompanyName,
account.Profile.Inn,
account.Profile.Description,
fullName,
account.Profile.AvatarUrl,
account.Profile.Competencies.Select(c => c.Name).ToList());

View File

@@ -27,5 +27,12 @@ public class RegisterUserCommandValidator : AbstractValidator<RegisterUserComman
RuleFor(x => x.CompanyName)
.NotEmpty().WithMessage("Название компании обязательно для юридических лиц")
.When(x => x.Role == Role.Company);
RuleFor(x => x.Inn)
.Length(10).WithMessage("ИНН должен содержать 10 цифр")
.When(x => x.Role == Role.Company);
RuleFor(x => x.Description)
.MaximumLength(2048).WithMessage("Описание не может превышать 2048 символов");
}
}

View File

@@ -14,5 +14,8 @@ public class UpdateProfileCommandValidator : AbstractValidator<UpdateProfileComm
RuleFor(x => x.LastName)
.NotEmpty().WithMessage("Фамилия обязательна")
.MinimumLength(2).WithMessage("Фамилия должна содержать минимум 2 символа");
RuleFor(x => x.Description)
.MaximumLength(2048).WithMessage("Описание не может превышать 2048 символов");
}
}

View File

@@ -6,38 +6,51 @@ namespace Nashel.Modules.Identity.Domain.Aggregates;
public class UserProfile : Entity<Guid>
{
private const int MaxCompetencies = 50;
private const int MaxDescriptionLength = 2048;
private readonly List<Competency> _competencies = new();
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string? Patronymic { get; private set; }
public string? CompanyName { get; private set; }
public string? Inn { get; private set; }
public string? Description { get; private set; }
public string? AvatarUrl { get; private set; }
public IReadOnlyCollection<Competency> Competencies => _competencies.AsReadOnly();
// EF Core constructor
private UserProfile() { }
private UserProfile(Guid id, string firstName, string lastName, string? patronymic, string? companyName)
private UserProfile(Guid id, string firstName, string lastName, string? patronymic, string? companyName, string? inn, string? description)
{
Id = id;
FirstName = firstName;
LastName = lastName;
Patronymic = patronymic;
CompanyName = companyName;
Inn = inn;
Description = description;
}
public static UserProfile Create(Guid id, string firstName, string lastName, string? patronymic, string? companyName)
public static UserProfile Create(Guid id, string firstName, string lastName, string? patronymic, string? companyName, string? inn, string? description)
{
return new UserProfile(id, firstName, lastName, patronymic, companyName);
if (!string.IsNullOrEmpty(description) && description.Length > MaxDescriptionLength)
throw new ArgumentException($"Описание не может превышать {MaxDescriptionLength} символов", nameof(description));
return new UserProfile(id, firstName, lastName, patronymic, companyName, inn, description);
}
public void Update(string firstName, string lastName, string? patronymic, string? companyName)
public void Update(string firstName, string lastName, string? patronymic, string? companyName, string? inn, string? description)
{
if (!string.IsNullOrEmpty(description) && description.Length > MaxDescriptionLength)
throw new ArgumentException($"Описание не может превышать {MaxDescriptionLength} символов", nameof(description));
FirstName = firstName;
LastName = lastName;
Patronymic = patronymic;
CompanyName = companyName;
Inn = inn;
Description = description;
}
public void UpdateAvatar(string? avatarUrl)
@@ -48,7 +61,7 @@ public class UserProfile : Entity<Guid>
public void UpdateCompetencies(IEnumerable<Competency> competencies)
{
var competencyList = competencies.ToList();
if (competencyList.Count > MaxCompetencies)
throw new InvalidOperationException($"Нельзя добавить больше {MaxCompetencies} компетенций");

View File

@@ -2,6 +2,7 @@ using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Nashel.Modules.Identity.Domain.Aggregates;
using Nashel.Modules.Identity.Domain.Entities;
using Nashel.Modules.Identity.Domain.Enums;
namespace Nashel.Modules.Identity.Infrastructure.Persistence.Configurations;
@@ -30,5 +31,11 @@ public class AccountConfiguration : IEntityTypeConfiguration<Account>
v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
v => JsonSerializer.Deserialize<List<Role>>(v, (JsonSerializerOptions?)null) ?? new List<Role>())
.HasColumnType("jsonb");
// Настройка связи с UserProfile (один-к-одному)
builder.HasOne(x => x.Profile)
.WithOne()
.HasForeignKey<UserProfile>(p => p.Id)
.OnDelete(DeleteBehavior.Cascade);
}
}

View File

@@ -28,6 +28,12 @@ public class UserProfileConfiguration : IEntityTypeConfiguration<UserProfile>
builder.Property(x => x.CompanyName)
.HasMaxLength(200);
builder.Property(x => x.Inn)
.HasMaxLength(10);
builder.Property(x => x.Description)
.HasMaxLength(2048);
builder.Property(x => x.AvatarUrl)
.HasMaxLength(500);

View File

@@ -0,0 +1,158 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Nashel.Modules.Identity.Infrastructure.Persistence;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Nashel.Modules.Identity.Infrastructure.Persistence.Migrations
{
[DbContext(typeof(IdentityDbContext))]
[Migration("20260215191454_AddDescriptionToUserProfile")]
partial class AddDescriptionToUserProfile
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("Roles")
.IsRequired()
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("Phone")
.IsUnique();
b.ToTable("Accounts", "identity");
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("AvatarUrl")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("CompanyName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Description")
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<string>("FirstName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("LastName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Patronymic")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.HasKey("Id");
b.ToTable("UserProfiles", "identity");
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Entities.Competency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique()
.HasDatabaseName("IX_Competencies_Name");
b.ToTable("Competencies", "identity");
});
modelBuilder.Entity("UserProfileCompetencies", b =>
{
b.Property<Guid>("UserProfileId")
.HasColumnType("uuid");
b.Property<Guid>("CompetencyId")
.HasColumnType("uuid");
b.HasKey("UserProfileId", "CompetencyId");
b.HasIndex("CompetencyId");
b.ToTable("UserProfileCompetencies", "identity");
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", b =>
{
b.HasOne("Nashel.Modules.Identity.Domain.Aggregates.Account", null)
.WithOne("Profile")
.HasForeignKey("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", "Id")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("UserProfileCompetencies", b =>
{
b.HasOne("Nashel.Modules.Identity.Domain.Entities.Competency", null)
.WithMany()
.HasForeignKey("CompetencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", null)
.WithMany()
.HasForeignKey("UserProfileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.Account", b =>
{
b.Navigation("Profile")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Nashel.Modules.Identity.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class AddDescriptionToUserProfile : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Description",
schema: "identity",
table: "UserProfiles",
type: "character varying(2048)",
maxLength: 2048,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Description",
schema: "identity",
table: "UserProfiles");
}
}
}

View File

@@ -0,0 +1,162 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Nashel.Modules.Identity.Infrastructure.Persistence;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Nashel.Modules.Identity.Infrastructure.Persistence.Migrations
{
[DbContext(typeof(IdentityDbContext))]
[Migration("20260215200327_AddInnToUserProfile")]
partial class AddInnToUserProfile
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("Roles")
.IsRequired()
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("Phone")
.IsUnique();
b.ToTable("Accounts", "identity");
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("AvatarUrl")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("CompanyName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Description")
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<string>("FirstName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Inn")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<string>("LastName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Patronymic")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.HasKey("Id");
b.ToTable("UserProfiles", "identity");
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Entities.Competency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique()
.HasDatabaseName("IX_Competencies_Name");
b.ToTable("Competencies", "identity");
});
modelBuilder.Entity("UserProfileCompetencies", b =>
{
b.Property<Guid>("UserProfileId")
.HasColumnType("uuid");
b.Property<Guid>("CompetencyId")
.HasColumnType("uuid");
b.HasKey("UserProfileId", "CompetencyId");
b.HasIndex("CompetencyId");
b.ToTable("UserProfileCompetencies", "identity");
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", b =>
{
b.HasOne("Nashel.Modules.Identity.Domain.Aggregates.Account", null)
.WithOne("Profile")
.HasForeignKey("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", "Id")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("UserProfileCompetencies", b =>
{
b.HasOne("Nashel.Modules.Identity.Domain.Entities.Competency", null)
.WithMany()
.HasForeignKey("CompetencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", null)
.WithMany()
.HasForeignKey("UserProfileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.Account", b =>
{
b.Navigation("Profile")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Nashel.Modules.Identity.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class AddInnToUserProfile : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Inn",
schema: "identity",
table: "UserProfiles",
type: "character varying(10)",
maxLength: 10,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Inn",
schema: "identity",
table: "UserProfiles");
}
}
}

View File

@@ -0,0 +1,162 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Nashel.Modules.Identity.Infrastructure.Persistence;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Nashel.Modules.Identity.Infrastructure.Persistence.Migrations
{
[DbContext(typeof(IdentityDbContext))]
[Migration("20260215202659_FixAccountProfileRelation")]
partial class FixAccountProfileRelation
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("character varying(20)");
b.Property<string>("Roles")
.IsRequired()
.HasColumnType("jsonb");
b.HasKey("Id");
b.HasIndex("Phone")
.IsUnique();
b.ToTable("Accounts", "identity");
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uuid");
b.Property<string>("AvatarUrl")
.HasMaxLength(500)
.HasColumnType("character varying(500)");
b.Property<string>("CompanyName")
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Description")
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<string>("FirstName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Inn")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<string>("LastName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Patronymic")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.HasKey("Id");
b.ToTable("UserProfiles", "identity");
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Entities.Competency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique()
.HasDatabaseName("IX_Competencies_Name");
b.ToTable("Competencies", "identity");
});
modelBuilder.Entity("UserProfileCompetencies", b =>
{
b.Property<Guid>("UserProfileId")
.HasColumnType("uuid");
b.Property<Guid>("CompetencyId")
.HasColumnType("uuid");
b.HasKey("UserProfileId", "CompetencyId");
b.HasIndex("CompetencyId");
b.ToTable("UserProfileCompetencies", "identity");
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", b =>
{
b.HasOne("Nashel.Modules.Identity.Domain.Aggregates.Account", null)
.WithOne("Profile")
.HasForeignKey("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", "Id")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("UserProfileCompetencies", b =>
{
b.HasOne("Nashel.Modules.Identity.Domain.Entities.Competency", null)
.WithMany()
.HasForeignKey("CompetencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Nashel.Modules.Identity.Domain.Aggregates.UserProfile", null)
.WithMany()
.HasForeignKey("UserProfileId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Nashel.Modules.Identity.Domain.Aggregates.Account", b =>
{
b.Navigation("Profile")
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Nashel.Modules.Identity.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class FixAccountProfileRelation : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

View File

@@ -62,11 +62,19 @@ namespace Nashel.Modules.Identity.Infrastructure.Persistence.Migrations
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("Description")
.HasMaxLength(2048)
.HasColumnType("character varying(2048)");
b.Property<string>("FirstName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)");
b.Property<string>("Inn")
.HasMaxLength(10)
.HasColumnType("character varying(10)");
b.Property<string>("LastName")
.IsRequired()
.HasMaxLength(100)

View File

@@ -16,6 +16,11 @@ public class AccountRepository : IAccountRepository
public async Task AddAsync(Account account, CancellationToken cancellationToken)
{
// Явно добавляем профиль, чтобы EF Core сохранил его в таблицу UserProfiles
if (account.Profile != null)
{
await _context.UserProfiles.AddAsync(account.Profile, cancellationToken);
}
await _context.Accounts.AddAsync(account, cancellationToken);
await _context.SaveChangesAsync(cancellationToken);
}
@@ -37,6 +42,11 @@ public class AccountRepository : IAccountRepository
public async Task UpdateAsync(Account account, CancellationToken cancellationToken)
{
// Явно обновляем профиль, чтобы EF Core сохранил изменения в таблицу UserProfiles
if (account.Profile != null)
{
_context.UserProfiles.Update(account.Profile);
}
_context.Accounts.Update(account);
await _context.SaveChangesAsync(cancellationToken);
}