EF - artemovsergey/ASP GitHub Wiki
public DbSet<User> Users => Set<User>();
public class DateTimeToCharConverter : ValueConverter<DateTime, string>
{
public DateTimeToCharConverter() : base(
dateTime => dateTime.ToString("yyyyMMdd", CultureInfo.InvariantCulture),
stringValue => DateTime.ParseExact(stringValue, "yyyyMMdd", CultureInfo.InvariantCulture)
)
{
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new GameMapping());
// modelBuilder.ApplyConfiguration(new UserMapping());
base.OnModelCreating(modelBuilder);
}
public class GameMapping : IEntityTypeConfiguration<Game>
{
public void Configure(EntityTypeBuilder<Game> builder)
{
builder.ToTable("Games").HasKey(g => g.Id);
builder.Property(g => g.CreatedAt)
.HasColumnType("timestamp with time zone");
//.HasConversion(new DateTimeToCharConverter());
builder.Property(g => g.Status).HasConversion<string>();
builder.Property(g => g.Result).HasConversion<string>();
builder.Property(g => g.CurrentMove).HasConversion<string>();
builder.Property(g => g.Board).HasConversion(
v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
v => JsonSerializer.Deserialize<string?[][]>(v, (JsonSerializerOptions?)null)!);
builder.Property(g => g.Board)
.HasConversion(
v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
v => JsonSerializer.Deserialize<string?[][]>(v, (JsonSerializerOptions?)null)!)
.Metadata.SetValueComparer(
new ValueComparer<string?[][]>(
(c1, c2) => c1!.SequenceEqual(c2!), // Сравниваем массивы поэлементно
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())), // Вычисляем хеш-код
c => c.Select(x => x.ToArray()).ToArray())); // Создаем глубокую копию для snapshot
// builder.HasOne(g => g.User)
// .WithMany(user => user.Games)
// .HasPrincipalKey(g =>g.Id)
// .HasForeignKey(u => u.UserId);
// Seed
builder.HasData(
new Game
{
Id = new Guid("b8aa36a5-9094-4dbd-80a5-444fcb92d3a4"), // Укажите явный Id (если есть)
Board = new string?[][]
{
new string?[] { "X", "O", null },
new string?[] { null, "X", "O" },
new string?[] { "O", null, "X" }
},
CreatedAt = new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc)
}
);
}
}
if (app.Environment.IsProduction())
{
using var scope = app.Services.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<TicTacToeContext>();
dbContext.Database.EnsureDeleted();
dbContext.Database.Migrate();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Configure indexes and relationships
ConfigureEntityRelationships(modelBuilder);
// Seed initial data
SeedInitialData(modelBuilder);
// Configure property conversions for User entity
ConfigureUserPropertyConversions(modelBuilder);
}
// Configure indexes and relationships
private void ConfigureEntityRelationships(ModelBuilder modelBuilder)
{
// Ensure Username is unique
modelBuilder.Entity<User>().HasIndex(u => u.Username).IsUnique();
// Configure one-to-many relationship between User and Record entities
modelBuilder.Entity<Record>()
.HasOne(p => p.User)
.WithMany(u => u.Records)
.HasForeignKey(p => p.UserId)
.OnDelete(DeleteBehavior.Cascade);
// Auto-include navigation property Records when querying User
modelBuilder.Entity<User>()
.Navigation(u => u.Records).AutoInclude();
}
// Seed initial data
private void SeedInitialData(ModelBuilder modelBuilder)
{
var user = User.CreateUser(new Username("SuperAdmin2077CP"),
new Password(HashPassword("qwerty28042002")),
new Email("[email protected]", true),
Role.Admin,
"ConfirmToken");
var record = new Record
{
Id = Guid.NewGuid(),
Title = "My day",
Url = new Uri("https://www.youtube.com/"),
DateCreated = DateTime.Now,
DeadLine = DateTime.Now.AddMonths(1),
Likes = 183,
DisLikes = 13,
IsPrivate = false,
UserId = user.Id,
};
// Add initial data to User and Record entities
modelBuilder.Entity<User>().HasData(user);
modelBuilder.Entity<Record>().HasData(record);
}
// Hash a password
private string HashPassword(string password)
{
var hashedBytes = SHA256.HashData(Encoding.UTF8.GetBytes(password));
var hash = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
return hash;
}
// Configure property conversions for User entity
private void ConfigureUserPropertyConversions(ModelBuilder modelBuilder)
{
// Configure conversion for Username property
modelBuilder.Entity<User>()
.Property(u => u.Username)
.HasConversion(
u => u.Value,
u => new Username(u));
// Configure conversion for Password property
modelBuilder.Entity<User>()
.Property(u => u.Password)
.HasConversion(
p => p.Value,
p => new Password(p));
// Configure conversion for Email property
modelBuilder.Entity<User>()
.Property(u => u.Email)
.HasConversion(
e => e.Value,
e => new Email(e, true));
}
Add-Migraion Init -Project "RusRoads.Application" -StartupProject "RusRoads.Application"
Update-database -Project "RusRoads.Application" -StartupProject "RusRoads.Application"
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//seed categories
modelBuilder.Entity<Country>().HasData(new Country { CountryId = 1, Name = "Belgium" });
modelBuilder.Entity<Country>().HasData(new Country { CountryId = 2, Name = "Germany" });
modelBuilder.Entity<Country>().HasData(new Country { CountryId = 3, Name = "Netherlands" });
modelBuilder.Entity<Country>().HasData(new Country { CountryId = 4, Name = "USA" });
modelBuilder.Entity<Country>().HasData(new Country { CountryId = 5, Name = "Japan" });
modelBuilder.Entity<Country>().HasData(new Country { CountryId = 6, Name = "China" });
modelBuilder.Entity<Country>().HasData(new Country { CountryId = 7, Name = "UK" });
modelBuilder.Entity<Country>().HasData(new Country { CountryId = 8, Name = "France" });
modelBuilder.Entity<Country>().HasData(new Country { CountryId = 9, Name = "Brazil" });
modelBuilder.Entity<JobCategory>().HasData(new JobCategory(){JobCategoryId = 1, JobCategoryName = "Pie research"});
modelBuilder.Entity<JobCategory>().HasData(new JobCategory(){JobCategoryId = 2, JobCategoryName = "Sales"});
modelBuilder.Entity<JobCategory>().HasData(new JobCategory(){JobCategoryId = 3, JobCategoryName = "Management"});
modelBuilder.Entity<JobCategory>().HasData(new JobCategory(){JobCategoryId = 4, JobCategoryName = "Store staff"});
modelBuilder.Entity<JobCategory>().HasData(new JobCategory(){JobCategoryId = 5, JobCategoryName = "Finance"});
modelBuilder.Entity<JobCategory>().HasData(new JobCategory(){JobCategoryId = 6, JobCategoryName = "QA"});
modelBuilder.Entity<JobCategory>().HasData(new JobCategory(){JobCategoryId = 7, JobCategoryName = "IT"});
modelBuilder.Entity<JobCategory>().HasData(new JobCategory(){JobCategoryId = 8, JobCategoryName = "Cleaning"});
modelBuilder.Entity<JobCategory>().HasData(new JobCategory(){JobCategoryId = 9, JobCategoryName = "Bakery"});
modelBuilder.Entity<Employee>().HasData(new Employee
{
EmployeeId = 1,
CountryId = 1,
MaritalStatus = MaritalStatus.Single,
BirthDate = new DateTime(1979, 1, 16),
City = "Brussels",
Email = "[email protected]",
FirstName = "Bethany",
LastName = "Smith",
Gender = Gender.Female,
PhoneNumber = "324777888773",
Smoker = false,
Street = "Grote Markt 1",
Zip = "1000",
JobCategoryId = 1,
Comment = "Lorem Ipsum",
ExitDate = null,
JoinedDate = new DateTime(2015, 3, 1),
Latitude = 50.8503,
Longitude = 4.3517
});
}
Если класс контекста лежит в другом проекте, то рядом с классом контекста создаем класс
public class ExampleContextFactory : IDesignTimeDbContextFactory<ExampleContext>
{
public ExampleContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<ExampleContext>();
optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Database=Example;Username=postgres;Password=root");
return new ExampleContext(optionsBuilder.Options);
}
}
API GetBooks возвращает коллекцию объектов Book. Ни одна из этих сущностей не изменяется. EF Core по умолчанию записывает все, что происходит с сущностями, которые он возвращает из запросов или добавляет в контекст. Эта функция, называемая отслеживанием изменений, является основной частью того, что делает EF Core таким мощным. Например, если код изменяет свойство Title объекта Book, EF Core записывает это изменение, а при вызове SaveChanges преобразует его в SQL-оператор UPDATE. Когда вы запрашиваете данные и не хотите вносить изменения, отключите отслеживание изменений, чтобы предотвратить случайные изменения, а также сэкономить память и процессор. На уровне запроса можно отключить отслеживание изменений с помощью метода расширения AsNoTracking.
В отличие от IEnumerable, который возвращает синхронный перечислитель. Синхронные перечислители позволяют избежать блокировки потоков, сначала получая все записи, а затем перечисляя их. Если вы хотите отправлять записи обратно в ответ по мере их получения из базы данных, не блокируя поток, IEnumerable не подойдет. IAsyncEnumerable позволяет действию начать отправку данных ответа, как только запрос базы данных начнет получать записи из базы данных. Без IAsyncEnumerable действие должно ждать отправки ответа, пока не будут получены все записи из базы данных и не будет готово полное содержимое ответа. Хотя это действие не имеет особых преимуществ для нашего примера, оно полезно для сервисов, которые работают с большим количеством данных (или медленными запросами).