Compare commits

..

9 Commits

Author SHA1 Message Date
f203ee71f0 fix: add an additional condition
All checks were successful
.NET Test Pipeline / build-and-test (push) Successful in 2m57s
Build and Deploy Docker Container / build-and-deploy (push) Successful in 3m36s
2024-10-27 07:14:30 +03:00
d8dbf1562f refactor: clean code 2024-10-27 06:51:05 +03:00
dead9f89bb feat: remove unused ref campus 2024-10-27 06:50:47 +03:00
8c932cf0be docs: update 2024-10-27 06:09:35 +03:00
80e74b34c1 feat: add background task 2024-10-27 05:42:50 +03:00
b095ca9749 feat: add sync and mapper schedule 2024-10-27 05:41:49 +03:00
8fad070a9c refactor: error logging 2024-10-27 04:36:20 +03:00
6c20713d81 feat: add docker as localhost 2024-10-27 04:09:31 +03:00
fc5ec1fd54 fix: log exception 2024-10-27 03:02:25 +03:00
34 changed files with 1956 additions and 248 deletions

View File

@ -1,36 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Mirea.Api.Dto.Responses;
/// <summary>
/// Represents detailed information about a faculty.
/// </summary>
public class FacultyDetailsResponse
{
/// <summary>
/// Gets or sets the unique identifier of the faculty.
/// </summary>
[Required]
public int Id { get; set; }
/// <summary>
/// Gets or sets the name of the faculty.
/// </summary>
[Required]
public required string Name { get; set; }
/// <summary>
/// Gets or sets the unique identifier of the campus to which the faculty belongs (optional).
/// </summary>
public int? CampusId { get; set; }
/// <summary>
/// Gets or sets the name of the campus to which the faculty belongs (optional).
/// </summary>
public string? CampusName { get; set; }
/// <summary>
/// Gets or sets the code name of the campus to which the faculty belongs (optional).
/// </summary>
public string? CampusCode { get; set; }
}

View File

@ -18,9 +18,4 @@ public class FacultyResponse
/// </summary> /// </summary>
[Required] [Required]
public required string Name { get; set; } public required string Name { get; set; }
/// <summary>
/// Gets or sets the unique identifier of the campus to which the faculty belongs (optional).
/// </summary>
public int? CampusId { get; set; }
} }

View File

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Net; using System.Net;
namespace Mirea.Api.Endpoint.Common.Attributes; namespace Mirea.Api.Endpoint.Common.Attributes;
@ -9,11 +10,21 @@ public class LocalhostAttribute : ActionFilterAttribute
public override void OnActionExecuting(ActionExecutingContext context) public override void OnActionExecuting(ActionExecutingContext context)
{ {
var ip = context.HttpContext.Connection.RemoteIpAddress; var ip = context.HttpContext.Connection.RemoteIpAddress;
if (ip == null || !IPAddress.IsLoopback(ip))
if (ip == null)
{ {
context.Result = new UnauthorizedResult(); context.Result = new UnauthorizedResult();
return; return;
} }
var isRunningInContainer = Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER")?.ToLower() == "true";
if (IPAddress.IsLoopback(ip) || (isRunningInContainer && ip.ToString().StartsWith("172.")))
{
base.OnActionExecuting(context); base.OnActionExecuting(context);
return;
}
context.Result = new UnauthorizedResult();
} }
} }

View File

@ -0,0 +1,15 @@
using System;
namespace Mirea.Api.Endpoint.Common.Services;
public static class ScheduleSyncManager
{
public static event Action? OnUpdateIntervalRequested;
public static event Action? OnForceSyncRequested;
public static void RequestIntervalUpdate() =>
OnUpdateIntervalRequested?.Invoke();
public static void RequestForceSync() =>
OnForceSyncRequested?.Invoke();
}

View File

@ -0,0 +1,120 @@
using Cronos;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Mirea.Api.Endpoint.Common.Services;
using Mirea.Api.Endpoint.Configuration.Model;
using Mirea.Api.Endpoint.Sync;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Mirea.Api.Endpoint.Configuration.Core.BackgroundTasks;
public class ScheduleSyncService : IHostedService, IDisposable
{
private Timer? _timer;
private readonly IOptionsMonitor<GeneralConfig> _generalConfigMonitor;
private readonly ILogger<ScheduleSyncService> _logger;
private CancellationTokenSource _cancellationTokenSource = new();
private readonly IServiceProvider _serviceProvider;
public ScheduleSyncService(IOptionsMonitor<GeneralConfig> generalConfigMonitor, ILogger<ScheduleSyncService> logger, IServiceProvider serviceProvider)
{
_generalConfigMonitor = generalConfigMonitor;
_logger = logger;
_serviceProvider = serviceProvider;
ScheduleSyncManager.OnForceSyncRequested += OnForceSyncRequested;
ScheduleSyncManager.OnUpdateIntervalRequested += OnUpdateIntervalRequested;
}
private void OnForceSyncRequested()
{
StopAsync(default).ContinueWith(_ =>
{
_cancellationTokenSource = new CancellationTokenSource();
ExecuteTask(null);
});
}
private void OnUpdateIntervalRequested()
{
StopAsync(default).ContinueWith(_ =>
{
StartAsync(default);
});
}
private void ScheduleNextRun()
{
var cronExpression = _generalConfigMonitor.CurrentValue.ScheduleSettings?.CronUpdateSchedule;
if (string.IsNullOrEmpty(cronExpression))
{
_logger.LogWarning("Cron expression is not set. The scheduled task will not run.");
return;
}
var nextRunTime = CronExpression.Parse(cronExpression).GetNextOccurrence(DateTimeOffset.Now, TimeZoneInfo.Local);
if (!nextRunTime.HasValue)
{
_logger.LogWarning("No next run time found. The task will not be scheduled. Timezone: {TimeZone}", TimeZoneInfo.Local.DisplayName);
return;
}
_logger.LogInformation("Next task run in {Time}", nextRunTime.Value.ToString("G"));
var delay = (nextRunTime.Value - DateTimeOffset.Now).TotalMilliseconds;
// The chance is small, but it's better to check
if (delay <= 0)
delay = 1;
_cancellationTokenSource = new CancellationTokenSource();
_timer = new Timer(ExecuteTask, null, (int)delay, Timeout.Infinite);
}
private async void ExecuteTask(object? state)
{
try
{
using var scope = _serviceProvider.CreateScope();
var syncService = ActivatorUtilities.GetServiceOrCreateInstance<ScheduleSynchronizer>(scope.ServiceProvider);
await syncService.StartSync(_cancellationTokenSource.Token);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred during schedule synchronization.");
}
finally
{
ScheduleNextRun();
}
}
public Task StartAsync(CancellationToken cancellationToken)
{
ScheduleNextRun();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_cancellationTokenSource.Cancel();
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
StopAsync(default).GetAwaiter().GetResult();
_timer?.Dispose();
ScheduleSyncManager.OnForceSyncRequested -= OnForceSyncRequested;
ScheduleSyncManager.OnUpdateIntervalRequested -= OnUpdateIntervalRequested;
_cancellationTokenSource.Dispose();
GC.SuppressFinalize(this);
}
}

View File

@ -1,5 +1,6 @@
using FluentValidation; using FluentValidation;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Mirea.Api.DataAccess.Application.Common.Exceptions; using Mirea.Api.DataAccess.Application.Common.Exceptions;
using Mirea.Api.Dto.Responses; using Mirea.Api.Dto.Responses;
using Mirea.Api.Endpoint.Common.Exceptions; using Mirea.Api.Endpoint.Common.Exceptions;
@ -9,7 +10,7 @@ using System.Threading.Tasks;
namespace Mirea.Api.Endpoint.Configuration.Core.Middleware; namespace Mirea.Api.Endpoint.Configuration.Core.Middleware;
public class CustomExceptionHandlerMiddleware(RequestDelegate next) public class CustomExceptionHandlerMiddleware(RequestDelegate next, ILogger<CustomExceptionHandlerMiddleware> logger)
{ {
public async Task InvokeAsync(HttpContext context) public async Task InvokeAsync(HttpContext context)
{ {
@ -23,7 +24,7 @@ public class CustomExceptionHandlerMiddleware(RequestDelegate next)
} }
} }
private static Task HandleExceptionAsync(HttpContext context, Exception exception) private Task HandleExceptionAsync(HttpContext context, Exception exception)
{ {
var code = StatusCodes.Status500InternalServerError; var code = StatusCodes.Status500InternalServerError;
var result = string.Empty; var result = string.Empty;
@ -48,10 +49,21 @@ public class CustomExceptionHandlerMiddleware(RequestDelegate next)
context.Response.ContentType = "application/json"; context.Response.ContentType = "application/json";
context.Response.StatusCode = code; context.Response.StatusCode = code;
if (string.IsNullOrEmpty(result)) if (!string.IsNullOrEmpty(result))
return context.Response.WriteAsync(result);
string error;
if (code == StatusCodes.Status500InternalServerError)
{
error = "Internal Server Error";
logger.LogError(exception, "Internal server error when processing the request");
}
else
error = exception.Message;
result = JsonSerializer.Serialize(new ErrorResponse() result = JsonSerializer.Serialize(new ErrorResponse()
{ {
Error = exception.Message, Error = error,
Code = code Code = code
}); });

View File

@ -161,13 +161,13 @@ public class SetupController(
} }
else if (Directory.GetDirectories(path).Length != 0 || else if (Directory.GetDirectories(path).Length != 0 ||
!Directory.GetFiles(path).Select(x => string.Equals(Path.GetFileName(x), "database.db3")).All(x => x)) !Directory.GetFiles(path).Select(x => string.Equals(Path.GetFileName(x), "database.db3")).All(x => x))
{
throw new ControllerArgumentException("Such a folder exists. Enter a different name"); throw new ControllerArgumentException("Such a folder exists. Enter a different name");
}
var filePath = Path.Combine(path, "database.db3"); var filePath = Path.Combine(path, "database.db3");
var connectionString = $"Data Source={filePath}"; var connectionString = $"Data Source={filePath}";
//System.IO.File.Create(filePath);
var result = SetDatabase<SqliteConnection, SqliteException>(connectionString, DbSettings.DatabaseEnum.Sqlite); var result = SetDatabase<SqliteConnection, SqliteException>(connectionString, DbSettings.DatabaseEnum.Sqlite);
foreach (var file in Directory.GetFiles(path)) foreach (var file in Directory.GetFiles(path))

View File

@ -1,7 +1,6 @@
using Asp.Versioning; using Asp.Versioning;
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Mirea.Api.DataAccess.Application.Cqrs.Faculty.Queries.GetFacultyDetails;
using Mirea.Api.DataAccess.Application.Cqrs.Faculty.Queries.GetFacultyList; using Mirea.Api.DataAccess.Application.Cqrs.Faculty.Queries.GetFacultyList;
using Mirea.Api.Dto.Responses; using Mirea.Api.Dto.Responses;
using Mirea.Api.Endpoint.Common.Attributes; using Mirea.Api.Endpoint.Common.Attributes;
@ -35,34 +34,8 @@ public class FacultyController(IMediator mediator) : BaseController
.Select(f => new FacultyResponse() .Select(f => new FacultyResponse()
{ {
Id = f.Id, Id = f.Id,
Name = f.Name, Name = f.Name
CampusId = f.CampusId
}) })
); );
} }
/// <summary>
/// Gets details of a specific faculty by ID.
/// </summary>
/// <param name="id">Faculty ID.</param>
/// <returns>Details of the specified faculty.</returns>
[HttpGet("{id:int}")]
[BadRequestResponse]
[NotFoundResponse]
public async Task<ActionResult<FacultyDetailsResponse>> GetDetails(int id)
{
var result = await mediator.Send(new GetFacultyInfoQuery()
{
Id = id
});
return Ok(new FacultyDetailsResponse()
{
Id = result.Id,
Name = result.Name,
CampusId = result.CampusId,
CampusCode = result.CampusCode,
CampusName = result.CampusName
});
}
} }

View File

@ -5,9 +5,9 @@
<ImplicitUsings>disable</ImplicitUsings> <ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Company>Winsomnia</Company> <Company>Winsomnia</Company>
<Version>1.0-rc3</Version> <Version>1.0-rc4</Version>
<AssemblyVersion>1.0.2.3</AssemblyVersion> <AssemblyVersion>1.0.2.4</AssemblyVersion>
<FileVersion>1.0.2.3</FileVersion> <FileVersion>1.0.2.4</FileVersion>
<AssemblyName>Mirea.Api.Endpoint</AssemblyName> <AssemblyName>Mirea.Api.Endpoint</AssemblyName>
<RootNamespace>$(AssemblyName)</RootNamespace> <RootNamespace>$(AssemblyName)</RootNamespace>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>

View File

@ -10,6 +10,7 @@ using Mirea.Api.DataAccess.Persistence;
using Mirea.Api.DataAccess.Persistence.Common; using Mirea.Api.DataAccess.Persistence.Common;
using Mirea.Api.Endpoint.Common.Interfaces; using Mirea.Api.Endpoint.Common.Interfaces;
using Mirea.Api.Endpoint.Common.Services; using Mirea.Api.Endpoint.Common.Services;
using Mirea.Api.Endpoint.Configuration.Core.BackgroundTasks;
using Mirea.Api.Endpoint.Configuration.Core.Middleware; using Mirea.Api.Endpoint.Configuration.Core.Middleware;
using Mirea.Api.Endpoint.Configuration.Core.Startup; using Mirea.Api.Endpoint.Configuration.Core.Startup;
using Mirea.Api.Endpoint.Configuration.Model; using Mirea.Api.Endpoint.Configuration.Model;
@ -63,6 +64,8 @@ public class Program
builder.Services.AddSingleton<IMaintenanceModeService, MaintenanceModeService>(); builder.Services.AddSingleton<IMaintenanceModeService, MaintenanceModeService>();
builder.Services.AddSingleton<ISetupToken, SetupTokenService>(); builder.Services.AddSingleton<ISetupToken, SetupTokenService>();
builder.Services.AddHostedService<ScheduleSyncService>();
builder.Services.AddMemoryCache(); builder.Services.AddMemoryCache();
builder.Services.AddCustomRedis(builder.Configuration, healthCheckBuilder); builder.Services.AddCustomRedis(builder.Configuration, healthCheckBuilder);

View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Mirea.Api.Endpoint.Sync.Common;
internal class DataRepository<T> where T : class
{
private readonly ConcurrentBag<T> _data = [];
private readonly object _lock = new();
public IEnumerable<T> GetAll() => _data.ToList();
public DataRepository(List<T> data)
{
foreach (var d in data)
_data.Add(d);
}
public T? Get(Func<T, bool> predicate)
{
var entity = _data.FirstOrDefault(predicate);
return entity;
}
public T Create(Func<T> createEntity)
{
var entity = createEntity();
_data.Add(entity);
return entity;
}
public T GetOrCreate(Func<T, bool> predicate, Func<T> createEntity)
{
lock (_lock)
{
var entity = Get(predicate);
return entity ?? Create(createEntity);
}
}
}

View File

@ -0,0 +1,289 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Mirea.Api.DataAccess.Domain.Schedule;
using Mirea.Api.DataAccess.Persistence;
using Mirea.Api.Endpoint.Common.Interfaces;
using Mirea.Api.Endpoint.Configuration.Model;
using Mirea.Api.Endpoint.Sync.Common;
using Mirea.Tools.Schedule.WebParser;
using Mirea.Tools.Schedule.WebParser.Common.Domain;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Group = Mirea.Api.DataAccess.Domain.Schedule.Group;
namespace Mirea.Api.Endpoint.Sync;
internal partial class ScheduleSynchronizer(UberDbContext dbContext, IOptionsSnapshot<GeneralConfig> config, ILogger<ScheduleSynchronizer> logger, IMaintenanceModeService maintenanceMode)
{
private readonly DataRepository<Campus> _campuses = new([.. dbContext.Campuses]);
private readonly DataRepository<Discipline> _disciplines = new([.. dbContext.Disciplines]);
private readonly DataRepository<Faculty> _faculties = new([.. dbContext.Faculties]);
private readonly DataRepository<Group> _groups = new([.. dbContext.Groups]);
private readonly DataRepository<LectureHall> _lectureHalls = new([.. dbContext.LectureHalls]);
private readonly DataRepository<Lesson> _lessons = new([]);
private readonly DataRepository<LessonAssociation> _lessonAssociation = new([]);
private readonly DataRepository<Professor> _professors = new([.. dbContext.Professors]);
private readonly DataRepository<TypeOfOccupation> _typeOfOccupations = new([.. dbContext.TypeOfOccupations]);
private readonly DataRepository<SpecificWeek> _specificWeeks = new([]);
// todo: transfer data to storage
private static string GetFaculty(char c) =>
c switch
{
'У' => "ИТУ",
'Б' => "ИКБ",
'Х' => "ИТХТ",
'Э' => "ИПТИП",
'Т' => "ИПТИП",
'Р' => "ИРИ",
'К' => "ИИИ",
'И' => "ИИТ",
'П' => "ИИТ",
_ => throw new ArgumentOutOfRangeException(nameof(c), c, null)
};
private void ParallelSync(GroupResult groupInfo)
{
var facultyName = GetFaculty(groupInfo.Group[0]);
var faculty = _faculties.GetOrCreate(
f => f.Name.Equals(facultyName, StringComparison.OrdinalIgnoreCase),
() => new Faculty
{
Name = facultyName
});
var groupName = OnlyGroupName().Match(groupInfo.Group.ToUpper()).Value;
var group = _groups.GetOrCreate(
g => g.Name.Equals(groupName, StringComparison.OrdinalIgnoreCase),
() => new Group
{
Name = groupName,
Faculty = faculty
});
var typeOfOccupation = _typeOfOccupations.GetOrCreate(
t => t.ShortName.Equals(groupInfo.TypeOfOccupation.Trim(), StringComparison.OrdinalIgnoreCase),
() => new TypeOfOccupation
{
ShortName = groupInfo.TypeOfOccupation.ToUpper()
});
List<Professor>? professor = [];
if (groupInfo.Professor != null)
{
foreach (var prof in groupInfo.Professor)
{
var professorParts = prof.Split(' ').ToList();
string? altName = null;
if (professorParts is { Count: >= 2 })
{
altName = professorParts.ElementAtOrDefault(0);
if (professorParts.ElementAtOrDefault(1) != null)
altName += $" {professorParts.ElementAtOrDefault(1)?[0]}.";
if (professorParts.ElementAtOrDefault(2) != null)
altName += $"{professorParts.ElementAtOrDefault(2)?[0]}.";
}
if (string.IsNullOrEmpty(altName))
continue;
var profDb = _professors.GetOrCreate(x =>
(x.AltName == null || x.AltName.Equals(prof, StringComparison.OrdinalIgnoreCase)) &&
x.Name.Equals(altName, StringComparison.OrdinalIgnoreCase),
() => new Professor
{
AltName = prof,
Name = altName
});
professor.Add(profDb);
}
}
else
professor = null;
List<LectureHall>? hall = null;
List<Campus>? campuses;
if (groupInfo.Campuses != null && groupInfo.Campuses.Length != 0)
{
hall = [];
campuses = [];
for (int i = 0; i < groupInfo.Campuses.Length; i++)
{
var campus = groupInfo.Campuses[i];
campuses.Add(_campuses.GetOrCreate(
c => c.CodeName.Equals(campus, StringComparison.OrdinalIgnoreCase),
() => new Campus
{
CodeName = campus.ToUpper()
}));
if (groupInfo.LectureHalls == null || groupInfo.LectureHalls.Length <= i)
continue;
var lectureHall = groupInfo.LectureHalls[i];
hall.Add(_lectureHalls.GetOrCreate(l =>
l.Name.Equals(lectureHall, StringComparison.OrdinalIgnoreCase) &&
string.Equals(l.Campus?.CodeName, campuses[^1].CodeName, StringComparison.CurrentCultureIgnoreCase),
() => new LectureHall
{
Name = lectureHall,
Campus = campuses[^1]
}));
}
}
var discipline = _disciplines.GetOrCreate(
d => d.Name.Equals(groupInfo.Discipline, StringComparison.OrdinalIgnoreCase),
() => new Discipline
{
Name = groupInfo.Discipline
});
var lesson = _lessons.GetOrCreate(l =>
l.IsEven == groupInfo.IsEven &&
l.DayOfWeek == groupInfo.Day &&
l.PairNumber == groupInfo.Pair &&
l.Discipline?.Name == discipline.Name &&
l.Group?.Name == group.Name,
() =>
{
var lesson = new Lesson
{
IsEven = groupInfo.IsEven,
DayOfWeek = groupInfo.Day,
PairNumber = groupInfo.Pair,
Discipline = discipline,
Group = group,
IsExcludedWeeks = groupInfo.IsExclude
};
if (groupInfo.SpecialWeek == null)
return lesson;
foreach (var week in groupInfo.SpecialWeek)
_specificWeeks.Create(() => new SpecificWeek
{
Lesson = lesson,
WeekNumber = week
});
return lesson;
});
int maxValue = int.Max(int.Max(professor?.Count ?? -1, hall?.Count ?? -1), 1);
for (int i = 0; i < maxValue; i++)
{
var prof = professor?.ElementAtOrDefault(i);
var lectureHall = hall?.ElementAtOrDefault(i);
_lessonAssociation.Create(() => new LessonAssociation
{
Professor = prof,
Lesson = lesson,
LectureHall = lectureHall,
TypeOfOccupation = typeOfOccupation
});
}
}
private async Task SaveChanges(CancellationToken cancellationToken)
{
foreach (var group in _groups.GetAll())
{
var existingGroup = await dbContext.Groups.FirstOrDefaultAsync(g => g.Id == group.Id, cancellationToken);
if (existingGroup != null)
dbContext.Remove(existingGroup);
}
await dbContext.Disciplines.BulkSynchronizeAsync(_disciplines.GetAll(), bulkOperation => bulkOperation.BatchSize = 1000, cancellationToken);
await dbContext.Professors.BulkSynchronizeAsync(_professors.GetAll(), bulkOperation => bulkOperation.BatchSize = 1000, cancellationToken);
await dbContext.TypeOfOccupations.BulkSynchronizeAsync(_typeOfOccupations.GetAll(), bulkOperation => bulkOperation.BatchSize = 100, cancellationToken);
await dbContext.Faculties.BulkSynchronizeAsync(_faculties.GetAll(), bulkOperation => bulkOperation.BatchSize = 100, cancellationToken);
await dbContext.Campuses.BulkSynchronizeAsync(_campuses.GetAll(), bulkOperation => bulkOperation.BatchSize = 10, cancellationToken);
await dbContext.LectureHalls.BulkSynchronizeAsync(_lectureHalls.GetAll(), bulkOperation => bulkOperation.BatchSize = 1000, cancellationToken);
await dbContext.Groups.BulkSynchronizeAsync(_groups.GetAll(), bulkOperation => bulkOperation.BatchSize = 100, cancellationToken);
await dbContext.Lessons.BulkSynchronizeAsync(_lessons.GetAll(), bulkOperation => bulkOperation.BatchSize = 1000, cancellationToken);
await dbContext.SpecificWeeks.BulkSynchronizeAsync(_specificWeeks.GetAll(), bulkOperation => bulkOperation.BatchSize = 1000, cancellationToken);
await dbContext.LessonAssociations.BulkSynchronizeAsync(_lessonAssociation.GetAll(), bulkOperation => bulkOperation.BatchSize = 1000, cancellationToken);
}
public async Task StartSync(CancellationToken cancellationToken)
{
var pairPeriods = config.Value.ScheduleSettings?.PairPeriod;
var startTerm = config.Value.ScheduleSettings?.StartTerm;
if (pairPeriods == null || startTerm == null)
{
logger.LogWarning("It is not possible to synchronize the schedule due to the fact that the {Arg1} or {Arg2} variable is not initialized.", nameof(pairPeriods), nameof(startTerm));
return;
}
Stopwatch watch = new();
watch.Start();
var parser = new Parser
{
Pairs = pairPeriods
.ToDictionary(x => x.Key,
x => (x.Value.Start, x.Value.End)),
TermStart = startTerm.Value.ToDateTime(new TimeOnly(0, 0, 0))
};
try
{
logger.LogDebug("Start parsing schedule");
var data = await parser.ParseAsync(cancellationToken);
watch.Stop();
var parsingTime = watch.ElapsedMilliseconds;
watch.Restart();
ParallelOptions options = new()
{
CancellationToken = cancellationToken,
MaxDegreeOfParallelism = Environment.ProcessorCount
};
logger.LogDebug("Start mapping parsed data");
Parallel.ForEach(data, options, ParallelSync);
watch.Stop();
var mappingTime = watch.ElapsedMilliseconds;
watch.Restart();
maintenanceMode.EnableMaintenanceMode();
logger.LogDebug("Start saving changing");
await SaveChanges(cancellationToken);
maintenanceMode.DisableMaintenanceMode();
watch.Stop();
logger.LogInformation("Parsing time: {ParsingTime}ms Mapping time: {MappingTime}ms Saving time: {SavingTime}ms Total time: {TotalTime}ms",
parsingTime, mappingTime, watch.ElapsedMilliseconds, parsingTime + mappingTime + watch.ElapsedMilliseconds);
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred during synchronization.");
maintenanceMode.DisableMaintenanceMode();
throw;
}
}
[GeneratedRegex(@"\w{4}-\d{2}-\d{2}(?=\s?\d?\s?[Пп]/?[Гг]\s?\d?)?")]
private static partial Regex OnlyGroupName();
}

View File

@ -35,7 +35,7 @@ Please note that the application will not work correctly if you do not fill in t
| Variable | Default | Description | Required | | Variable | Default | Description | Required |
|---------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------| |---------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|
| PATH_TO_SAVE | | The path to save the data. Saving logs (if the full path is not specified), databases (if Sqlite), and other data that should be saved in a place other than where the program is launched. | ✔ | | PATH_TO_SAVE | Current folder | The path to save the data. Saving logs (if the full path is not specified), databases (if Sqlite), and other data that should be saved in a place other than where the program is launched. | ✔ |
| SECURITY_SIGNING_TOKEN | ❌ | JWT signature token. This token will be used to create and verify the signature of JWT tokens. The token must be equal to 64 characters. | ✔ | | SECURITY_SIGNING_TOKEN | ❌ | JWT signature token. This token will be used to create and verify the signature of JWT tokens. The token must be equal to 64 characters. | ✔ |
| SECURITY_ENCRYPTION_TOKEN | ❌ | Token for JWT encryption. This token will be used to encrypt and decrypt JWT tokens. The token must be equal to 32 characters. | ✔ | | SECURITY_ENCRYPTION_TOKEN | ❌ | Token for JWT encryption. This token will be used to encrypt and decrypt JWT tokens. The token must be equal to 32 characters. | ✔ |
| SECURITY_LIFE_TIME_RT | 1440 | Time in minutes after which the Refresh Token will become invalid. | ❌ | | SECURITY_LIFE_TIME_RT | 1440 | Time in minutes after which the Refresh Token will become invalid. | ❌ |
@ -170,7 +170,7 @@ Install git in advance or clone the repository in another way.
```bash ```bash
git clone https://git.winsomnia.net/Winsomnia/MireaBackend.git \ git clone https://git.winsomnia.net/Winsomnia/MireaBackend.git \
cd DoctorTelegramBot cd MireaBackend
``` ```
### Build Self Release ### Build Self Release

View File

@ -5,9 +5,9 @@
<ImplicitUsings>disable</ImplicitUsings> <ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Company>Winsomnia</Company> <Company>Winsomnia</Company>
<Version>1.0.1</Version> <Version>1.0.2</Version>
<AssemblyVersion>1.0.3.1</AssemblyVersion> <AssemblyVersion>1.0.3.2</AssemblyVersion>
<FileVersion>1.0.3.1</FileVersion> <FileVersion>1.0.3.2</FileVersion>
<AssemblyName>Mirea.Api.DataAccess.Application</AssemblyName> <AssemblyName>Mirea.Api.DataAccess.Application</AssemblyName>
<RootNamespace>$(AssemblyName)</RootNamespace> <RootNamespace>$(AssemblyName)</RootNamespace>
</PropertyGroup> </PropertyGroup>

View File

@ -1,32 +0,0 @@
namespace Mirea.Api.DataAccess.Application.Cqrs.Faculty.Queries.GetFacultyDetails;
/// <summary>
/// Represents faculties.
/// </summary>
public class FacultyInfoVm
{
/// <summary>
/// The unique identifier for the faculty.
/// </summary>
public int Id { get; set; }
/// <summary>
/// The name of the faculty.
/// </summary>
public required string Name { get; set; }
/// <summary>
/// ID indicating the faculty's affiliation to the campus.
/// </summary>
public int? CampusId { get; set; }
/// <summary>
/// Campus name indicating the faculty's affiliation to the campus.
/// </summary>
public string? CampusName { get; set; }
/// <summary>
/// Campus code indicating the faculty's affiliation to the campus.
/// </summary>
public string? CampusCode { get; set; }
}

View File

@ -1,8 +0,0 @@
using MediatR;
namespace Mirea.Api.DataAccess.Application.Cqrs.Faculty.Queries.GetFacultyDetails;
public class GetFacultyInfoQuery : IRequest<FacultyInfoVm>
{
public required int Id { get; set; }
}

View File

@ -1,27 +0,0 @@
using MediatR;
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Application.Common.Exceptions;
using Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
using System.Threading;
using System.Threading.Tasks;
namespace Mirea.Api.DataAccess.Application.Cqrs.Faculty.Queries.GetFacultyDetails;
public class GetFacultyInfoQueryHandler(IFacultyDbContext dbContext) : IRequestHandler<GetFacultyInfoQuery, FacultyInfoVm>
{
public async Task<FacultyInfoVm> Handle(GetFacultyInfoQuery request, CancellationToken cancellationToken)
{
var faculty = await dbContext.Faculties
.Include(f => f.Campus)
.FirstOrDefaultAsync(f => f.Id == request.Id, cancellationToken) ?? throw new NotFoundException(typeof(Domain.Schedule.Faculty), request.Id);
return new FacultyInfoVm()
{
Id = faculty.Id,
Name = faculty.Name,
CampusId = faculty.CampusId,
CampusName = faculty.Campus?.FullName,
CampusCode = faculty.Campus?.CodeName
};
}
}

View File

@ -14,8 +14,7 @@ public class GetFacultyListQueryHandler(IFacultyDbContext dbContext) : IRequestH
var dtos = dbContext.Faculties.OrderBy(f => f.Id).Select(f => new FacultyLookupDto() var dtos = dbContext.Faculties.OrderBy(f => f.Id).Select(f => new FacultyLookupDto()
{ {
Id = f.Id, Id = f.Id,
Name = f.Name, Name = f.Name
CampusId = f.CampusId
}); });
if (request is { PageSize: not null, Page: not null }) if (request is { PageSize: not null, Page: not null })

View File

@ -5,9 +5,9 @@
<ImplicitUsings>disable</ImplicitUsings> <ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Company>Winsomnia</Company> <Company>Winsomnia</Company>
<Version>1.0.0</Version> <Version>1.0.1</Version>
<AssemblyVersion>1.0.3.0</AssemblyVersion> <AssemblyVersion>1.0.3.1</AssemblyVersion>
<FileVersion>1.0.3.0</FileVersion> <FileVersion>1.0.3.1</FileVersion>
<AssemblyName>Mirea.Api.DataAccess.Domain</AssemblyName> <AssemblyName>Mirea.Api.DataAccess.Domain</AssemblyName>
<RootNamespace>$(AssemblyName)</RootNamespace> <RootNamespace>$(AssemblyName)</RootNamespace>
</PropertyGroup> </PropertyGroup>

View File

@ -9,6 +9,5 @@ public class Campus
public string? FullName { get; set; } public string? FullName { get; set; }
public string? Address { get; set; } public string? Address { get; set; }
public List<Faculty>? Faculties { get; set; }
public List<LectureHall>? LectureHalls { get; set; } public List<LectureHall>? LectureHalls { get; set; }
} }

View File

@ -7,8 +7,5 @@ public class Faculty
public int Id { get; set; } public int Id { get; set; }
public required string Name { get; set; } public required string Name { get; set; }
public int? CampusId { get; set; }
public Campus? Campus { get; set; }
public List<Group>? Groups { get; set; } public List<Group>? Groups { get; set; }
} }

View File

@ -0,0 +1,425 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Mirea.Api.DataAccess.Persistence;
#nullable disable
namespace MysqlMigrations.Migrations
{
[DbContext(typeof(UberDbContext))]
[Migration("20241027034820_RemoveUnusedRef")]
partial class RemoveUnusedRef
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Address")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<string>("CodeName")
.IsRequired()
.HasMaxLength(16)
.HasColumnType("TEXT");
b.Property<string>("FullName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Campus", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Discipline", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Discipline", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Faculty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Faculty", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int?>("FacultyId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("FacultyId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Group", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("CampusId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CampusId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("LectureHall", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Lesson", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("DayOfWeek")
.HasColumnType("INTEGER");
b.Property<int>("DisciplineId")
.HasColumnType("INTEGER");
b.Property<int>("GroupId")
.HasColumnType("INTEGER");
b.Property<bool>("IsEven")
.HasColumnType("BOOLEAN");
b.Property<bool?>("IsExcludedWeeks")
.HasColumnType("BOOLEAN");
b.Property<int>("PairNumber")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("DisciplineId");
b.HasIndex("GroupId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Lesson", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LessonAssociation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int?>("LectureHallId")
.HasColumnType("INTEGER");
b.Property<int>("LessonId")
.HasColumnType("INTEGER");
b.Property<string>("LinkToMeet")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<int?>("ProfessorId")
.HasColumnType("INTEGER");
b.Property<int>("TypeOfOccupationId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("LectureHallId");
b.HasIndex("LessonId");
b.HasIndex("ProfessorId");
b.HasIndex("TypeOfOccupationId");
b.ToTable("LessonAssociation", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Professor", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("AltName")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Professor", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.SpecificWeek", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int>("LessonId")
.HasColumnType("INTEGER");
b.Property<int>("WeekNumber")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("LessonId");
b.ToTable("SpecificWeek", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.TypeOfOccupation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<string>("ShortName")
.IsRequired()
.HasMaxLength(16)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("TypeOfOccupation", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Faculty", "Faculty")
.WithMany("Groups")
.HasForeignKey("FacultyId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Faculty");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Campus", "Campus")
.WithMany("LectureHalls")
.HasForeignKey("CampusId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Campus");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Lesson", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Discipline", "Discipline")
.WithMany("Lessons")
.HasForeignKey("DisciplineId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Group", "Group")
.WithMany("Lessons")
.HasForeignKey("GroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Discipline");
b.Navigation("Group");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LessonAssociation", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", "LectureHall")
.WithMany("LessonAssociations")
.HasForeignKey("LectureHallId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Lesson", "Lesson")
.WithMany("LessonAssociations")
.HasForeignKey("LessonId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Professor", "Professor")
.WithMany("LessonAssociations")
.HasForeignKey("ProfessorId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.TypeOfOccupation", "TypeOfOccupation")
.WithMany("Lessons")
.HasForeignKey("TypeOfOccupationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LectureHall");
b.Navigation("Lesson");
b.Navigation("Professor");
b.Navigation("TypeOfOccupation");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.SpecificWeek", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Lesson", "Lesson")
.WithMany("SpecificWeeks")
.HasForeignKey("LessonId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Lesson");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b =>
{
b.Navigation("LectureHalls");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Discipline", b =>
{
b.Navigation("Lessons");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Faculty", b =>
{
b.Navigation("Groups");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{
b.Navigation("Lessons");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", b =>
{
b.Navigation("LessonAssociations");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Lesson", b =>
{
b.Navigation("LessonAssociations");
b.Navigation("SpecificWeeks");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Professor", b =>
{
b.Navigation("LessonAssociations");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.TypeOfOccupation", b =>
{
b.Navigation("Lessons");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,83 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MysqlMigrations.Migrations
{
/// <inheritdoc />
public partial class RemoveUnusedRef : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Faculty_Campus_CampusId",
table: "Faculty");
migrationBuilder.DropIndex(
name: "IX_Faculty_CampusId",
table: "Faculty");
migrationBuilder.DropColumn(
name: "CampusId",
table: "Faculty");
migrationBuilder.AlterColumn<bool>(
name: "IsExcludedWeeks",
table: "Lesson",
type: "BOOLEAN(1)",
nullable: true,
oldClrType: typeof(ulong),
oldType: "BIT(1)",
oldNullable: true);
migrationBuilder.AlterColumn<bool>(
name: "IsEven",
table: "Lesson",
type: "BOOLEAN(1)",
nullable: false,
oldClrType: typeof(ulong),
oldType: "BIT(1)");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<ulong>(
name: "IsExcludedWeeks",
table: "Lesson",
type: "BIT(1)",
nullable: true,
oldClrType: typeof(bool),
oldType: "BOOLEAN(1)",
oldNullable: true);
migrationBuilder.AlterColumn<ulong>(
name: "IsEven",
table: "Lesson",
type: "BIT(1)",
nullable: false,
oldClrType: typeof(bool),
oldType: "BOOLEAN(1)");
migrationBuilder.AddColumn<int>(
name: "CampusId",
table: "Faculty",
type: "INTEGER",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Faculty_CampusId",
table: "Faculty",
column: "CampusId");
migrationBuilder.AddForeignKey(
name: "FK_Faculty_Campus_CampusId",
table: "Faculty",
column: "CampusId",
principalTable: "Campus",
principalColumn: "Id",
onDelete: ReferentialAction.SetNull);
}
}
}

View File

@ -17,7 +17,7 @@ namespace MysqlMigrations.Migrations
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "8.0.6") .HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 64); .HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
@ -80,9 +80,6 @@ namespace MysqlMigrations.Migrations
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id")); MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<int?>("CampusId")
.HasColumnType("INTEGER");
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasMaxLength(256) .HasMaxLength(256)
@ -90,8 +87,6 @@ namespace MysqlMigrations.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CampusId");
b.HasIndex("Id") b.HasIndex("Id")
.IsUnique(); .IsUnique();
@ -168,10 +163,10 @@ namespace MysqlMigrations.Migrations
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<bool>("IsEven") b.Property<bool>("IsEven")
.HasColumnType("BIT(1)"); .HasColumnType("BOOLEAN");
b.Property<bool?>("IsExcludedWeeks") b.Property<bool?>("IsExcludedWeeks")
.HasColumnType("BIT(1)"); .HasColumnType("BOOLEAN");
b.Property<int>("PairNumber") b.Property<int>("PairNumber")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
@ -296,16 +291,6 @@ namespace MysqlMigrations.Migrations
b.ToTable("TypeOfOccupation", (string)null); b.ToTable("TypeOfOccupation", (string)null);
}); });
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Faculty", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Campus", "Campus")
.WithMany("Faculties")
.HasForeignKey("CampusId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Campus");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b => modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{ {
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Faculty", "Faculty") b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Faculty", "Faculty")
@ -392,8 +377,6 @@ namespace MysqlMigrations.Migrations
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b => modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b =>
{ {
b.Navigation("Faculties");
b.Navigation("LectureHalls"); b.Navigation("LectureHalls");
}); });

View File

@ -0,0 +1,425 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Mirea.Api.DataAccess.Persistence;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace PsqlMigrations.Migrations
{
[DbContext(typeof(UberDbContext))]
[Migration("20241027032753_RemoveUnusedRef")]
partial class RemoveUnusedRef
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Address")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<string>("CodeName")
.IsRequired()
.HasMaxLength(16)
.HasColumnType("TEXT");
b.Property<string>("FullName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Campus", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Discipline", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Discipline", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Faculty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Faculty", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int?>("FacultyId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("FacultyId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Group", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("CampusId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CampusId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("LectureHall", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Lesson", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("DayOfWeek")
.HasColumnType("INTEGER");
b.Property<int>("DisciplineId")
.HasColumnType("INTEGER");
b.Property<int>("GroupId")
.HasColumnType("INTEGER");
b.Property<bool>("IsEven")
.HasColumnType("BOOLEAN");
b.Property<bool?>("IsExcludedWeeks")
.HasColumnType("BOOLEAN");
b.Property<int>("PairNumber")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("DisciplineId");
b.HasIndex("GroupId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Lesson", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LessonAssociation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int?>("LectureHallId")
.HasColumnType("INTEGER");
b.Property<int>("LessonId")
.HasColumnType("INTEGER");
b.Property<string>("LinkToMeet")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<int?>("ProfessorId")
.HasColumnType("INTEGER");
b.Property<int>("TypeOfOccupationId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("LectureHallId");
b.HasIndex("LessonId");
b.HasIndex("ProfessorId");
b.HasIndex("TypeOfOccupationId");
b.ToTable("LessonAssociation", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Professor", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("AltName")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Professor", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.SpecificWeek", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("LessonId")
.HasColumnType("INTEGER");
b.Property<int>("WeekNumber")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("LessonId");
b.ToTable("SpecificWeek", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.TypeOfOccupation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ShortName")
.IsRequired()
.HasMaxLength(16)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("TypeOfOccupation", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Faculty", "Faculty")
.WithMany("Groups")
.HasForeignKey("FacultyId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Faculty");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Campus", "Campus")
.WithMany("LectureHalls")
.HasForeignKey("CampusId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Campus");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Lesson", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Discipline", "Discipline")
.WithMany("Lessons")
.HasForeignKey("DisciplineId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Group", "Group")
.WithMany("Lessons")
.HasForeignKey("GroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Discipline");
b.Navigation("Group");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LessonAssociation", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", "LectureHall")
.WithMany("LessonAssociations")
.HasForeignKey("LectureHallId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Lesson", "Lesson")
.WithMany("LessonAssociations")
.HasForeignKey("LessonId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Professor", "Professor")
.WithMany("LessonAssociations")
.HasForeignKey("ProfessorId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.TypeOfOccupation", "TypeOfOccupation")
.WithMany("Lessons")
.HasForeignKey("TypeOfOccupationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LectureHall");
b.Navigation("Lesson");
b.Navigation("Professor");
b.Navigation("TypeOfOccupation");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.SpecificWeek", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Lesson", "Lesson")
.WithMany("SpecificWeeks")
.HasForeignKey("LessonId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Lesson");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b =>
{
b.Navigation("LectureHalls");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Discipline", b =>
{
b.Navigation("Lessons");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Faculty", b =>
{
b.Navigation("Groups");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{
b.Navigation("Lessons");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", b =>
{
b.Navigation("LessonAssociations");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Lesson", b =>
{
b.Navigation("LessonAssociations");
b.Navigation("SpecificWeeks");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Professor", b =>
{
b.Navigation("LessonAssociations");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.TypeOfOccupation", b =>
{
b.Navigation("Lessons");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,49 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PsqlMigrations.Migrations
{
/// <inheritdoc />
public partial class RemoveUnusedRef : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Faculty_Campus_CampusId",
table: "Faculty");
migrationBuilder.DropIndex(
name: "IX_Faculty_CampusId",
table: "Faculty");
migrationBuilder.DropColumn(
name: "CampusId",
table: "Faculty");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "CampusId",
table: "Faculty",
type: "INTEGER",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Faculty_CampusId",
table: "Faculty",
column: "CampusId");
migrationBuilder.AddForeignKey(
name: "FK_Faculty_Campus_CampusId",
table: "Faculty",
column: "CampusId",
principalTable: "Campus",
principalColumn: "Id",
onDelete: ReferentialAction.SetNull);
}
}
}

View File

@ -17,7 +17,7 @@ namespace PsqlMigrations.Migrations
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "8.0.6") .HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63); .HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@ -80,9 +80,6 @@ namespace PsqlMigrations.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int?>("CampusId")
.HasColumnType("INTEGER");
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasMaxLength(256) .HasMaxLength(256)
@ -90,8 +87,6 @@ namespace PsqlMigrations.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CampusId");
b.HasIndex("Id") b.HasIndex("Id")
.IsUnique(); .IsUnique();
@ -296,16 +291,6 @@ namespace PsqlMigrations.Migrations
b.ToTable("TypeOfOccupation", (string)null); b.ToTable("TypeOfOccupation", (string)null);
}); });
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Faculty", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Campus", "Campus")
.WithMany("Faculties")
.HasForeignKey("CampusId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Campus");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b => modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{ {
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Faculty", "Faculty") b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Faculty", "Faculty")
@ -392,8 +377,6 @@ namespace PsqlMigrations.Migrations
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b => modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b =>
{ {
b.Navigation("Faculties");
b.Navigation("LectureHalls"); b.Navigation("LectureHalls");
}); });

View File

@ -0,0 +1,400 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Mirea.Api.DataAccess.Persistence;
#nullable disable
namespace SqliteMigrations.Migrations
{
[DbContext(typeof(UberDbContext))]
[Migration("20241027032931_RemoveUnusedRef")]
partial class RemoveUnusedRef
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.10");
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Address")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<string>("CodeName")
.IsRequired()
.HasMaxLength(16)
.HasColumnType("TEXT");
b.Property<string>("FullName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Campus", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Discipline", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Discipline", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Faculty", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Faculty", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int?>("FacultyId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("FacultyId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Group", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CampusId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CampusId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("LectureHall", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Lesson", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("DayOfWeek")
.HasColumnType("INTEGER");
b.Property<int>("DisciplineId")
.HasColumnType("INTEGER");
b.Property<int>("GroupId")
.HasColumnType("INTEGER");
b.Property<bool>("IsEven")
.HasColumnType("BOOLEAN");
b.Property<bool?>("IsExcludedWeeks")
.HasColumnType("BOOLEAN");
b.Property<int>("PairNumber")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("DisciplineId");
b.HasIndex("GroupId");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Lesson", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LessonAssociation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int?>("LectureHallId")
.HasColumnType("INTEGER");
b.Property<int>("LessonId")
.HasColumnType("INTEGER");
b.Property<string>("LinkToMeet")
.HasMaxLength(512)
.HasColumnType("TEXT");
b.Property<int?>("ProfessorId")
.HasColumnType("INTEGER");
b.Property<int>("TypeOfOccupationId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("LectureHallId");
b.HasIndex("LessonId");
b.HasIndex("ProfessorId");
b.HasIndex("TypeOfOccupationId");
b.ToTable("LessonAssociation", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Professor", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AltName")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("Professor", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.SpecificWeek", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("LessonId")
.HasColumnType("INTEGER");
b.Property<int>("WeekNumber")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.HasIndex("LessonId");
b.ToTable("SpecificWeek", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.TypeOfOccupation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ShortName")
.IsRequired()
.HasMaxLength(16)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Id")
.IsUnique();
b.ToTable("TypeOfOccupation", (string)null);
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Faculty", "Faculty")
.WithMany("Groups")
.HasForeignKey("FacultyId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Faculty");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Campus", "Campus")
.WithMany("LectureHalls")
.HasForeignKey("CampusId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Campus");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Lesson", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Discipline", "Discipline")
.WithMany("Lessons")
.HasForeignKey("DisciplineId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Group", "Group")
.WithMany("Lessons")
.HasForeignKey("GroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Discipline");
b.Navigation("Group");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LessonAssociation", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", "LectureHall")
.WithMany("LessonAssociations")
.HasForeignKey("LectureHallId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Lesson", "Lesson")
.WithMany("LessonAssociations")
.HasForeignKey("LessonId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Professor", "Professor")
.WithMany("LessonAssociations")
.HasForeignKey("ProfessorId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.TypeOfOccupation", "TypeOfOccupation")
.WithMany("Lessons")
.HasForeignKey("TypeOfOccupationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("LectureHall");
b.Navigation("Lesson");
b.Navigation("Professor");
b.Navigation("TypeOfOccupation");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.SpecificWeek", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Lesson", "Lesson")
.WithMany("SpecificWeeks")
.HasForeignKey("LessonId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Lesson");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b =>
{
b.Navigation("LectureHalls");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Discipline", b =>
{
b.Navigation("Lessons");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Faculty", b =>
{
b.Navigation("Groups");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{
b.Navigation("Lessons");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.LectureHall", b =>
{
b.Navigation("LessonAssociations");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Lesson", b =>
{
b.Navigation("LessonAssociations");
b.Navigation("SpecificWeeks");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Professor", b =>
{
b.Navigation("LessonAssociations");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.TypeOfOccupation", b =>
{
b.Navigation("Lessons");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,49 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SqliteMigrations.Migrations
{
/// <inheritdoc />
public partial class RemoveUnusedRef : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Faculty_Campus_CampusId",
table: "Faculty");
migrationBuilder.DropIndex(
name: "IX_Faculty_CampusId",
table: "Faculty");
migrationBuilder.DropColumn(
name: "CampusId",
table: "Faculty");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "CampusId",
table: "Faculty",
type: "INTEGER",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Faculty_CampusId",
table: "Faculty",
column: "CampusId");
migrationBuilder.AddForeignKey(
name: "FK_Faculty_Campus_CampusId",
table: "Faculty",
column: "CampusId",
principalTable: "Campus",
principalColumn: "Id",
onDelete: ReferentialAction.SetNull);
}
}
}

View File

@ -15,7 +15,7 @@ namespace SqliteMigrations.Migrations
protected override void BuildModel(ModelBuilder modelBuilder) protected override void BuildModel(ModelBuilder modelBuilder)
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.6"); modelBuilder.HasAnnotation("ProductVersion", "8.0.10");
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b => modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b =>
{ {
@ -69,9 +69,6 @@ namespace SqliteMigrations.Migrations
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<int?>("CampusId")
.HasColumnType("INTEGER");
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasMaxLength(256) .HasMaxLength(256)
@ -79,8 +76,6 @@ namespace SqliteMigrations.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CampusId");
b.HasIndex("Id") b.HasIndex("Id")
.IsUnique(); .IsUnique();
@ -271,16 +266,6 @@ namespace SqliteMigrations.Migrations
b.ToTable("TypeOfOccupation", (string)null); b.ToTable("TypeOfOccupation", (string)null);
}); });
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Faculty", b =>
{
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Campus", "Campus")
.WithMany("Faculties")
.HasForeignKey("CampusId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Campus");
});
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b => modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Group", b =>
{ {
b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Faculty", "Faculty") b.HasOne("Mirea.Api.DataAccess.Domain.Schedule.Faculty", "Faculty")
@ -367,8 +352,6 @@ namespace SqliteMigrations.Migrations
modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b => modelBuilder.Entity("Mirea.Api.DataAccess.Domain.Schedule.Campus", b =>
{ {
b.Navigation("Faculties");
b.Navigation("LectureHalls"); b.Navigation("LectureHalls");
}); });

View File

@ -14,13 +14,5 @@ public class FacultyConfiguration : IEntityTypeConfiguration<Faculty>
builder.Property(f => f.Id).HasColumnType("INT").IsRequired().ValueGeneratedOnAdd(); builder.Property(f => f.Id).HasColumnType("INT").IsRequired().ValueGeneratedOnAdd();
builder.Property(f => f.Name).HasColumnType("VARCHAR(256)").IsRequired().HasMaxLength(256); builder.Property(f => f.Name).HasColumnType("VARCHAR(256)").IsRequired().HasMaxLength(256);
builder.Property(f => f.CampusId).HasColumnType("INT");
builder
.HasOne(f => f.Campus)
.WithMany(c => c.Faculties)
.HasForeignKey(c => c.CampusId)
.OnDelete(DeleteBehavior.SetNull);
} }
} }

View File

@ -14,13 +14,5 @@ public class FacultyConfiguration : IEntityTypeConfiguration<Faculty>
builder.Property(f => f.Id).HasColumnType("serial").IsRequired().ValueGeneratedOnAdd(); builder.Property(f => f.Id).HasColumnType("serial").IsRequired().ValueGeneratedOnAdd();
builder.Property(f => f.Name).HasColumnType("text").IsRequired().HasMaxLength(256); builder.Property(f => f.Name).HasColumnType("text").IsRequired().HasMaxLength(256);
builder.Property(f => f.CampusId).HasColumnType("serial");
builder
.HasOne(f => f.Campus)
.WithMany(c => c.Faculties)
.HasForeignKey(c => c.CampusId)
.OnDelete(DeleteBehavior.SetNull);
} }
} }

View File

@ -14,13 +14,5 @@ public class FacultyConfiguration : IEntityTypeConfiguration<Faculty>
builder.Property(f => f.Id).HasColumnType("INTEGER").IsRequired().ValueGeneratedOnAdd(); builder.Property(f => f.Id).HasColumnType("INTEGER").IsRequired().ValueGeneratedOnAdd();
builder.Property(f => f.Name).HasColumnType("TEXT").IsRequired().HasMaxLength(256); builder.Property(f => f.Name).HasColumnType("TEXT").IsRequired().HasMaxLength(256);
builder.Property(f => f.CampusId).HasColumnType("INTEGER");
builder
.HasOne(f => f.Campus)
.WithMany(c => c.Faculties)
.HasForeignKey(c => c.CampusId)
.OnDelete(DeleteBehavior.SetNull);
} }
} }

View File

@ -5,9 +5,9 @@
<ImplicitUsings>disable</ImplicitUsings> <ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Company>Winsomnia</Company> <Company>Winsomnia</Company>
<Version>1.0.1</Version> <Version>1.0.2</Version>
<AssemblyVersion>1.0.3.1</AssemblyVersion> <AssemblyVersion>1.0.3.2</AssemblyVersion>
<FileVersion>1.0.3.1</FileVersion> <FileVersion>1.0.3.2</FileVersion>
<AssemblyName>Mirea.Api.DataAccess.Persistence</AssemblyName> <AssemblyName>Mirea.Api.DataAccess.Persistence</AssemblyName>
<RootNamespace>$(AssemblyName)</RootNamespace> <RootNamespace>$(AssemblyName)</RootNamespace>
</PropertyGroup> </PropertyGroup>