Add services and controllers for games (#12)

Co-authored-by: Maxime Adler <madler@sqli.com>
Reviewed-on: #12
This commit was merged in pull request #12.
This commit is contained in:
2025-04-12 21:34:45 +02:00
parent 3537465588
commit 3ea96186e7
32 changed files with 531 additions and 23 deletions

View File

@@ -21,7 +21,7 @@ public partial class GameFilter
]; ];
private readonly IEnumerable<SelectElement<Func<GameDto?, object?>>> GameProperties = [ private readonly IEnumerable<SelectElement<Func<GameDto?, object?>>> GameProperties = [
new() { Item = game => game?.Name, Label = "Nom", IsSelected = true }, new() { Item = game => game?.Title, Label = "Nom", IsSelected = true },
new() { Item = game => game?.ReleaseDate, Label = "Date de parution" } new() { Item = game => game?.ReleaseDate, Label = "Date de parution" }
]; ];
@@ -40,7 +40,7 @@ public partial class GameFilter
]; ];
private EditContext? EditContext; private EditContext? EditContext;
private SliderRangeParams SliderRangeParams = private readonly SliderRangeParams SliderRangeParams =
new() { Min = 1, ValueMin = 1, ValueMax = 5, Max = 5 }; new() { Min = 1, ValueMin = 1, ValueMax = 5, Max = 5 };
protected override void OnInitialized() protected override void OnInitialized()

View File

@@ -9,10 +9,10 @@
<PageTitle>@ResourcesKey.GamesIdeas</PageTitle> <PageTitle>@ResourcesKey.GamesIdeas</PageTitle>
<GamesHeader> <GameHeader>
<GameFilter @bind-DisplayType=DisplayType <GameFilter @bind-DisplayType=DisplayType
@bind-GameFilterParams=GameFilterParams /> @bind-GameFilterParams=GameFilterParams />
</GamesHeader> </GameHeader>
<div class="container"> <div class="container">
<div class="content"> <div class="content">

View File

@@ -3,7 +3,7 @@ using GameIdeas.BlazorApp.Shared.Models;
namespace GameIdeas.BlazorApp.Pages.Games; namespace GameIdeas.BlazorApp.Pages.Games;
public partial class GamesBase () public partial class GameBase ()
{ {
private DisplayType DisplayType = DisplayType.List; private DisplayType DisplayType = DisplayType.List;
private GameFilterParams GameFilterParams = new(); private GameFilterParams GameFilterParams = new();

View File

@@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Components;
namespace GameIdeas.BlazorApp.Pages.Games.Header; namespace GameIdeas.BlazorApp.Pages.Games.Header;
public partial class GamesHeader : ComponentBase public partial class GameHeader : ComponentBase
{ {
[Parameter] public EventCallback<AddType> AddTypeChanged { get; set; } [Parameter] public EventCallback<AddType> AddTypeChanged { get; set; }
[Parameter] public RenderFragment? ChildContent { get; set; } [Parameter] public RenderFragment? ChildContent { get; set; }

View File

@@ -0,0 +1,7 @@
namespace GameIdeas.Shared.Dto;
public class DeveloperDto
{
public int? Id { get; set; }
public string? Name { get; set; }
}

View File

@@ -2,6 +2,21 @@
public class GameDto public class GameDto
{ {
public string? Name { get; set; } public int? Id { get; set; }
public string? ReleaseDate { get; set; } public string? Title { get; set; }
public DateTime? ReleaseDate { get; set; }
public DateTime? CreationDate { get; set; }
public UserDto? CreationUser { get; set; }
public int? CreationUserId { get; set; }
public DateTime? ModificationDate { get; set; }
public UserDto? ModificationUser { get; set; }
public int? ModificationUserId { get; set; }
public double? StorageSpace { get; set; }
public string? Description { get; set; }
public int? Interest { get; set; }
public IEnumerable<PlatformDto>? Platforms { get; set; }
public IEnumerable<PropertyDto>? Properties { get; set; }
public IEnumerable<TagDto>? Tags { get; set; }
public IEnumerable<PublisherDto>? Publishers { get; set; }
public IEnumerable<DeveloperDto>? Developers { get; set; }
} }

View File

@@ -0,0 +1,16 @@
namespace GameIdeas.Shared.Dto;
public class GameFilterDto
{
public IEnumerable<string>? Platforms { get; set; }
public string? Name { get; set; }
public IEnumerable<string>? Tags { get; set; }
public IEnumerable<string>? Properties { get; set; }
public int? MinInterest { get; set; }
public int? MaxInterest { get; set; }
public IEnumerable<int>? ReleaseYears { get; set; }
public IEnumerable<int>? PublisherIds { get; set; }
public IEnumerable<int>? DeveloperIds { get; set; }
public IEnumerable<int>? CreationUserIds { get; set; }
public IEnumerable<int>? ModificationUserIds { get; set; }
}

View File

@@ -1,7 +1,11 @@
namespace GameIdeas.Shared.Dto; using GameIdeas.Shared.Enum;
namespace GameIdeas.Shared.Dto;
public class LoginDto public class LoginDto
{ {
public int? Id { get; set; }
public string? Username { get; set; } public string? Username { get; set; }
public string? Password { get; set; } public string? Password { get; set; }
public Role? Role { get; set; }
} }

View File

@@ -0,0 +1,7 @@
namespace GameIdeas.Shared.Dto;
public class PaggingDto
{
public int CurrentPage { get; set; }
public int NumberPerPage { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace GameIdeas.Shared.Dto;
public class PlatformDto
{
public int? Id { get; set; }
public string? Label { get; set; }
public string? Url { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace GameIdeas.Shared.Dto;
public class PropertyDto
{
public int? Id { get; set; }
public string? Label { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace GameIdeas.Shared.Dto;
public class PublisherDto
{
public int? Id { get; set; }
public string? Name { get; set; }
}

View File

@@ -0,0 +1,8 @@

namespace GameIdeas.Shared.Dto;
public class TagDto
{
public int? Id { get; set; }
public string? Label { get; set; }
}

View File

@@ -0,0 +1,11 @@
using GameIdeas.Shared.Enum;
namespace GameIdeas.Shared.Dto;
public class UserDto
{
public int? Id { get; set; }
public string? Username { get; set; }
public string? Password { get; set; }
public Role? Role { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace GameIdeas.Shared.Enum;
public enum Role
{
Guest = 1,
Member = 2,
Administrator = 3
}

View File

@@ -0,0 +1,3 @@
namespace GameIdeas.Shared.Exceptions;
public class NotFoundException(string msg, Exception? innerException = null) : Exception(msg, innerException);

View File

@@ -8,7 +8,7 @@ public partial class Platform
} }
public int Id { get; set; } public int Id { get; set; }
public string Libelle { get; set; } = null!; public string Label { get; set; } = null!;
public virtual ICollection<GamePlatform> GamePlatforms { get; set; } public virtual ICollection<GamePlatform> GamePlatforms { get; set; }

View File

@@ -7,7 +7,10 @@ public class GameIdeasContext : DbContext
{ {
public GameIdeasContext(DbContextOptions<GameIdeasContext> option) public GameIdeasContext(DbContextOptions<GameIdeasContext> option)
: base(option) : base(option)
{ } {
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
}
public virtual DbSet<User> Users { get; set; } = null!; public virtual DbSet<User> Users { get; set; } = null!;
public virtual DbSet<Developer> Developers { get; set; } = null!; public virtual DbSet<Developer> Developers { get; set; } = null!;

View File

@@ -0,0 +1,83 @@
using GameIdeas.Shared.Dto;
using GameIdeas.WebAPI.Services;
using Microsoft.AspNetCore.Mvc;
namespace GameIdeas.WebAPI.Controllers;
[ApiController]
[Route("api/[controller]")]
public class GameController(GameService gameService, ILoggerFactory loggerFactory) : Controller
{
private readonly ILogger<GameController> logger = loggerFactory.CreateLogger<GameController>();
[HttpGet]
public async Task<ActionResult<IEnumerable<GameDto>>> SearchGames([FromQuery] PaggingDto pagging)
{
try
{
return Ok(await gameService.GetGames(pagging));
}
catch (Exception e)
{
logger.LogError(e, "Internal error while search games");
return StatusCode(500, e.Message);
}
}
[HttpGet("{id:int}")]
public async Task<ActionResult<GameDto>> GetGameById(int id)
{
try
{
return Ok(await gameService.GetGameById(id));
}
catch (Exception e)
{
logger.LogError(e, "Internal error while get game with id {id}", id);
return StatusCode(500, e.Message);
}
}
[HttpPost("Create")]
public async Task<ActionResult<GameDto>> CreateGame([FromBody] GameDto game)
{
try
{
return Created("/Create", await gameService.CreateGame(game));
}
catch (Exception e)
{
logger.LogError(e, "Internal error while create game");
return StatusCode(500, e.Message);
}
}
[HttpPut("Update")]
public async Task<ActionResult<GameDto>> UpdateGame([FromBody] GameDto game)
{
try
{
return Created($"/Update", await gameService.UpdateGame(game));
}
catch (Exception e)
{
logger.LogError(e, "Internal error while update game");
return StatusCode(500, e.Message);
}
}
[HttpDelete("Delete/{id:int}")]
public async Task<ActionResult<bool>> DeleteGame(int id)
{
try
{
return Ok(await gameService.DeleteGame(id));
}
catch (Exception e)
{
logger.LogError(e, "Internal error while delete game");
return StatusCode(500, e.Message);
}
}
}

View File

@@ -11,6 +11,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoMapper" Version="14.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4">

View File

@@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace GameIdeas.WebAPI.Migrations namespace GameIdeas.WebAPI.Migrations
{ {
[DbContext(typeof(GameIdeasContext))] [DbContext(typeof(GameIdeasContext))]
[Migration("20250409210640_InitialCreate")] [Migration("20250409225125_InitialCreate")]
partial class InitialCreate partial class InitialCreate
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -176,7 +176,7 @@ namespace GameIdeas.WebAPI.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Libelle") b.Property<string>("Label")
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");

View File

@@ -31,7 +31,7 @@ namespace GameIdeas.WebAPI.Migrations
{ {
Id = table.Column<int>(type: "integer", nullable: false) Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Libelle = table.Column<string>(type: "text", nullable: false) Label = table.Column<string>(type: "text", nullable: false)
}, },
constraints: table => constraints: table =>
{ {

View File

@@ -173,7 +173,7 @@ namespace GameIdeas.WebAPI.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Libelle") b.Property<string>("Label")
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");

View File

@@ -0,0 +1,83 @@
using AutoMapper;
using GameIdeas.Shared.Dto;
using GameIdeas.Shared.Model;
namespace GameIdeas.WebAPI.Profiles;
public class CategoryProfile : Profile
{
public CategoryProfile()
{
CreatePlaformMap();
CreatePropertyMap();
CreateTagMap();
CreateDeveloperMap();
CreatePublisherMap();
}
private void CreatePublisherMap()
{
CreateMap<Publisher, PublisherDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Name, o => o.MapFrom(s => s.Name))
.ReverseMap();
CreateMap<PublisherDto, GamePublisher>()
.ForMember(d => d.PublisherId, o => o.MapFrom(s => s.Id))
.ForPath(d => d.Publisher.Id, o => o.MapFrom(s => s.Id))
.ForPath(d => d.Publisher.Name, o => o.MapFrom(s => s.Name));
}
private void CreateDeveloperMap()
{
CreateMap<Developer, DeveloperDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Name, o => o.MapFrom(s => s.Name))
.ReverseMap();
CreateMap<DeveloperDto, GameDeveloper>()
.ForMember(d => d.DeveloperId, o => o.MapFrom(s => s.Id))
.ForPath(d => d.Developer.Id, o => o.MapFrom(s => s.Id))
.ForPath(d => d.Developer.Name, o => o.MapFrom(s => s.Name));
}
private void CreateTagMap()
{
CreateMap<Tag, TagDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Label, o => o.MapFrom(s => s.Label))
.ReverseMap();
CreateMap<TagDto, GameTag>()
.ForMember(d => d.TagId, o => o.MapFrom(s => s.Id))
.ForPath(d => d.Tag.Id, o => o.MapFrom(s => s.Id))
.ForPath(d => d.Tag.Label, o => o.MapFrom(s => s.Label));
}
private void CreatePropertyMap()
{
CreateMap<Property, PropertyDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Label, o => o.MapFrom(s => s.Label))
.ReverseMap();
CreateMap<PropertyDto, GameProperty>()
.ForMember(d => d.PropertyId, o => o.MapFrom(s => s.Id))
.ForPath(d => d.Property.Id, o => o.MapFrom(s => s.Id))
.ForPath(d => d.Property.Label, o => o.MapFrom(s => s.Label));
}
private void CreatePlaformMap()
{
CreateMap<Platform, PlatformDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Label, o => o.MapFrom(s => s.Label))
.ReverseMap();
CreateMap<PlatformDto, GamePlatform>()
.ForMember(d => d.PlatformId, o => o.MapFrom(s => s.Id))
.ForPath(d => d.Platform.Id, o => o.MapFrom(s => s.Id))
.ForPath(d => d.Platform.Label, o => o.MapFrom(s => s.Label))
.ForMember(d => d.Url, o => o.MapFrom(s => s.Url));
}
}

View File

@@ -0,0 +1,31 @@
using AutoMapper;
using GameIdeas.Shared.Dto;
using GameIdeas.Shared.Model;
namespace GameIdeas.WebAPI.Profiles;
public class GameProfile : Profile
{
public GameProfile()
{
CreateMap<Game, GameDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Title, o => o.MapFrom(s => s.Title))
.ForMember(d => d.ReleaseDate, o => o.MapFrom(s => s.ReleaseDate))
.ForMember(d => d.CreationDate, o => o.MapFrom(s => s.CreationDate))
.ForMember(d => d.CreationUserId, o => o.MapFrom(s => s.CreationUserId))
.ForMember(d => d.CreationUser, o => o.MapFrom(s => s.CreationUser))
.ForMember(d => d.ModificationDate, o => o.MapFrom(s => s.ModificationDate))
.ForMember(d => d.ModificationUserId, o => o.MapFrom(s => s.ModificationUserId))
.ForMember(d => d.ModificationUser, o => o.MapFrom(s => s.ModificationUser))
.ForMember(d => d.StorageSpace, o => o.MapFrom(s => s.StorageSpace))
.ForMember(d => d.Description, o => o.MapFrom(s => s.Description))
.ForMember(d => d.Interest, o => o.MapFrom(s => s.Interest))
.ForMember(d => d.Platforms, o => o.MapFrom(s => s.GamePlatforms.Select(p => new PlatformDto() { Id = p.Platform.Id, Label = p.Platform.Label, Url = p.Url })))
.ForMember(d => d.Properties, o => o.MapFrom(s => s.GameProperties.Select(p => p.Property)))
.ForMember(d => d.Tags, o => o.MapFrom(s => s.GameTags.Select(t => t.Tag)))
.ForMember(d => d.Publishers, o => o.MapFrom(s => s.GamePublishers.Select(p => p.Publisher)))
.ForMember(d => d.Developers, o => o.MapFrom(s => s.GameDevelopers.Select(gd => gd.Developer)))
.ReverseMap();
}
}

View File

@@ -0,0 +1,20 @@
using AutoMapper;
using GameIdeas.Shared.Dto;
using GameIdeas.Shared.Enum;
using GameIdeas.Shared.Model;
namespace GameIdeas.WebAPI.Profiles;
public class UserProfile : Profile
{
public UserProfile()
{
CreateMap<User, UserDto>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
.ForMember(d => d.Username, o => o.MapFrom(s => s.Username))
.ForMember(d => d.Password, o => o.MapFrom(s => s.Password))
.ForMember(d => d.Role, o => o.MapFrom(s => s.Role))
.ReverseMap();
}
}

View File

@@ -1,17 +1,17 @@
using GameIdeas.Resources; using GameIdeas.Resources;
using GameIdeas.WebAPI.Context; using GameIdeas.WebAPI.Context;
using GameIdeas.WebAPI.Profiles;
using GameIdeas.WebAPI.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using System.Text.Json.Serialization;
using System.Data;
using System.Data.Common;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
var services = builder.Services; var services = builder.Services;
#if DEBUG #if DEBUG
Load("../../../../.env"); LoadEnvironmentVariable("../../../../.env");
#else #else
Load(".env"); LoadEnvironmentVariable(".env");
#endif #endif
Action<DbContextOptionsBuilder> dbContextOptions = options => Action<DbContextOptionsBuilder> dbContextOptions = options =>
@@ -22,8 +22,7 @@ Action<DbContextOptionsBuilder> dbContextOptions = options =>
{ {
npgOption.CommandTimeout(60); npgOption.CommandTimeout(60);
npgOption.MigrationsAssembly("GameIdeas.WebAPI"); npgOption.MigrationsAssembly("GameIdeas.WebAPI");
}) });
.LogTo(Console.WriteLine);
}; };
// Add services to the container. // Add services to the container.
@@ -32,7 +31,14 @@ services.AddDbContext<GameIdeasContext>(dbContextOptions);
services.AddSingleton<TranslationService>(); services.AddSingleton<TranslationService>();
services.AddSingleton<Translations>(); services.AddSingleton<Translations>();
services.AddScoped<GameService>();
services.AddAutoMapper(typeof(GameProfile).Assembly);
services.AddAutoMapper(typeof(UserProfile).Assembly);
services.AddAutoMapper(typeof(CategoryProfile).Assembly);
services.AddControllers(); services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
services.AddOpenApi(); services.AddOpenApi();
@@ -40,6 +46,7 @@ services.AddCors(option => option.AddDefaultPolicy(policy =>
policy.WithOrigins("http://localhost:5172", "http://localhost:7060") policy.WithOrigins("http://localhost:5172", "http://localhost:7060")
.AllowAnyHeader() .AllowAnyHeader()
.WithMethods("GET", "POST", "PUT", "DELETE"))); .WithMethods("GET", "POST", "PUT", "DELETE")));
var app = builder.Build(); var app = builder.Build();
await LoadTranslations(); await LoadTranslations();
@@ -85,7 +92,7 @@ string GetConnectionString()
return $"Host={host};Username={login};Password={pass};Database={database}"; return $"Host={host};Username={login};Password={pass};Database={database}";
} }
static void Load(string filePath) static void LoadEnvironmentVariable(string filePath)
{ {
if (!File.Exists(filePath)) if (!File.Exists(filePath))
return; return;

View File

@@ -0,0 +1,174 @@
using AutoMapper;
using GameIdeas.Shared.Dto;
using GameIdeas.Shared.Exceptions;
using GameIdeas.Shared.Model;
using GameIdeas.WebAPI.Context;
using Microsoft.EntityFrameworkCore;
namespace GameIdeas.WebAPI.Services;
public class GameService(GameIdeasContext context, IMapper mapper)
{
public async Task<IEnumerable<GameDto>> GetGames(PaggingDto pagging)
{
var games = await SelectGames()
.OrderBy(g => g.Title)
.Skip((pagging.CurrentPage - 1) * pagging.NumberPerPage)
.Take(pagging.NumberPerPage)
.ToListAsync();
return mapper.Map<IEnumerable<GameDto>>(games);
}
public async Task<GameDto> GetGameById(int gameId)
{
var game = await SelectGames()
.FirstOrDefaultAsync(g => g.Id == gameId);
return game == null
? throw new NotFoundException($"[{typeof(Game).FullName}] with ID {gameId} has not been found in context")
: mapper.Map<GameDto>(game);
}
public async Task<GameDto> CreateGame(GameDto gameDto)
{
var gameToCreate = mapper.Map<Game>(gameDto);
await context.Games.AddAsync(gameToCreate);
await context.SaveChangesAsync();
await HandlePlatformsCreation(gameDto.Platforms, gameToCreate.Id);
await HandlePropertiesCreation(gameDto.Properties, gameToCreate.Id);
await HandleTagsCreation(gameDto.Tags, gameToCreate.Id);
await HandlePublishersCreation(gameDto.Publishers, gameToCreate.Id);
await HandleDevelopersCreation(gameDto.Developers, gameToCreate.Id);
await context.SaveChangesAsync();
return mapper.Map<GameDto>(gameToCreate);
}
public async Task<GameDto> UpdateGame(GameDto gameDto)
{
if (await context.Games.CountAsync(g => g.Id == gameDto.Id) == 0)
{
throw new NotFoundException($"[{typeof(Game).FullName}] with ID {gameDto.Id} has not been found in context");
}
var gameToUpdate = mapper.Map<Game>(gameDto);
await HandlePlatformsCreation(gameDto.Platforms, gameToUpdate.Id);
await HandlePropertiesCreation(gameDto.Properties, gameToUpdate.Id);
await HandleTagsCreation(gameDto.Tags, gameToUpdate.Id);
await HandlePublishersCreation(gameDto.Publishers, gameToUpdate.Id);
await HandleDevelopersCreation(gameDto.Developers, gameToUpdate.Id);
context.Games.Update(gameToUpdate);
await context.SaveChangesAsync();
return mapper.Map<GameDto>(gameToUpdate);
}
public async Task<bool> DeleteGame(int gameId)
{
var gameToRemove = await context.Games
.FirstOrDefaultAsync(g => g.Id == gameId)
?? throw new NotFoundException($"[{typeof(Game).FullName}] with ID {gameId} has not been found in context");
context.Games.Remove(gameToRemove);
return await context.SaveChangesAsync() != 0;
}
private IQueryable<Game> SelectGames()
{
return context.Games
.Include(g => g.CreationUser)
.Include(g => g.ModificationUser)
.Include(g => g.GamePlatforms).ThenInclude(p => p.Platform)
.Include(g => g.GameProperties).ThenInclude(p => p.Property)
.Include(g => g.GameTags).ThenInclude(p => p.Tag)
.Include(g => g.GamePublishers).ThenInclude(p => p.Publisher)
.Include(g => g.GameDevelopers).ThenInclude(p => p.Developer)
.AsQueryable();
}
private async Task HandlePlatformsCreation(IEnumerable<PlatformDto>? categoriesToCreate, int gameId)
{
if (categoriesToCreate != null)
{
var gps = mapper.Map<ICollection<GamePlatform>>(categoriesToCreate);
foreach (var gp in gps)
{
gp.GameId = gameId;
}
context.Platforms.AttachRange(gps.Select(gp => gp.Platform));
await context.GamePlatforms.AddRangeAsync(gps);
}
}
private async Task HandlePropertiesCreation(IEnumerable<PropertyDto>? categoriesToCreate, int gameId)
{
if (categoriesToCreate != null)
{
var gps = mapper.Map<ICollection<GameProperty>>(categoriesToCreate);
foreach (var gp in gps)
{
gp.GameId = gameId;
}
context.Properties.AttachRange(gps.Select(gp => gp.Property));
await context.GameProperties.AddRangeAsync(gps);
}
}
private async Task HandleTagsCreation(IEnumerable<TagDto>? categoriesToCreate, int gameId)
{
if (categoriesToCreate != null)
{
var gts = mapper.Map<ICollection<GameTag>>(categoriesToCreate);
foreach (var gt in gts)
{
gt.GameId = gameId;
}
context.Tags.AttachRange(gts.Select(gt => gt.Tag));
await context.GameTags.AddRangeAsync(gts);
}
}
private async Task HandlePublishersCreation(IEnumerable<PublisherDto>? categoriesToCreate, int gameId)
{
if (categoriesToCreate != null)
{
var gps = mapper.Map<ICollection<GamePublisher>>(categoriesToCreate);
foreach (var gp in gps)
{
gp.GameId = gameId;
}
context.Publishers.AttachRange(gps.Select(gp => gp.Publisher));
await context.GamePublishers.AddRangeAsync(gps);
}
}
private async Task HandleDevelopersCreation(IEnumerable<DeveloperDto>? categoriesToCreate, int gameId)
{
if (categoriesToCreate != null)
{
var gds = mapper.Map<ICollection<GameDeveloper>>(categoriesToCreate);
foreach (var gd in gds)
{
gd.GameId = gameId;
}
context.Developers.AttachRange(gds.Select(gd => gd.Developer));
await context.GameDevelopers.AddRangeAsync(gds);
}
}
}

View File

@@ -0,0 +1,5 @@
namespace GameIdeas.WebAPI.Services;
public class UserService
{
}