using System.Linq.Expressions; using System.Reflection; using Back.Program.Common.Auth; using Back.Program.Common.Data; using Back.Program.Common.Model; using Back.Program.Models.Entities; using Microsoft.EntityFrameworkCore; namespace Back.Program.Services.V1 { public interface IRepositoryService { // Task ValidateToken(string token, string refresh); Task SaveData(T entity, Expression> key = null) where T : class; Task DeleteData(T entity, Expression> key = null) where T : class; String ReadSummary(Type type, String name); } public class RepositoryService: IRepositoryService { private readonly AppDbContext _dbContext; private readonly ILogger _logger; private readonly JwtTokenService _jwtTokenService; public RepositoryService(AppDbContext dbContext, ILogger logger, JwtTokenService jwtTokenService) { _dbContext = dbContext; _logger = logger; _jwtTokenService = jwtTokenService; } // public async Task ValidateToken(string token, string refresh) // { // var principalToken = await _jwtTokenService.ValidateToken(token); // if (principalToken != null) // { // var uid = principalToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; // _logger.LogInformation($"토큰 변환 - {uid}"); // return new ValidateToken // { // token = token, // refresh = refresh, // uid = uid // }; // } // else // { // _logger.LogInformation("엑세스 토큰 만료"); // // var refreshToken = await _dbContext.RefreshTokens // // .FirstOrDefaultAsync(t => t.refresh_token == refresh); // // if (refreshToken == null) // // throw new TokenException("입력 받은 토큰 자체의 문제"); // // // // var uid = refreshToken.uid; // // // // if (refreshToken.revoke_Date < DateTime.Now) // // throw new RefreshRevokeException("리프레시 토큰 해지"); // // // // if (refreshToken.expire_date > DateTime.Now) // // { // // _logger.LogInformation($"인증 완료 리프레시 : {uid}"); // // var access = _jwtTokenService.GenerateJwtToken(uid); // // // // return new ValidateToken // // { // // token = access, // // refresh = refreshToken.refresh_token, // // uid = uid // // }; // // } // // else // // { // // refreshToken = _jwtTokenService.GenerateRefreshToken(uid); // // _logger.LogInformation("리프레시 토큰 만료"); // // // await SaveData(refreshToken, rt => rt.uid); // // return new ValidateToken // // { // // token = token, // // refresh = refreshToken.refresh_token, // // uid = uid // // }; // // } // } // } public async Task SaveData(T entity, Expression> key = null) where T : class { try { if (key != null) { // key를 가지고 EF 로 돌리는게 아니라 내가 조건을 넣어서 하는 경우에 사용함 var value = key.Compile()(entity); var parameter = Expression.Parameter(typeof(T), "x"); var invokedExpr = Expression.Invoke(key, parameter); var constantExpr = Expression.Constant(value, key.Body.Type); var equalsExpr = Expression.Equal(invokedExpr, constantExpr); var predicate = Expression.Lambda>(equalsExpr, parameter); var entityData = await _dbContext.Set().FirstOrDefaultAsync(predicate); if (entityData != null) { _logger.LogInformation($"[{typeof(T)}] 해당 PK 존재 = [{value}]: 계속"); _dbContext.Entry(entityData).CurrentValues.SetValues(entity); if (!(_dbContext.Entry(entityData).Properties.Any(p => p.IsModified))) { _logger.LogInformation($"[{typeof(T)}] 변경 사항 없음"); return true; } _logger.LogInformation($"[{typeof(T)}] 변경 사항이 존재"); } else { _logger.LogInformation($"[{typeof(T)}] 처음등록"); _dbContext.Set().Add(entity); } } else { // EF 로 직접 키를 잡아서 사용 (관계키나 이런거 할때도 노상관됨) // 모델이 존재하지 않거나 기본 키 정의가 되지 않은 오류가 발생할 건데 그건 운영 단계에서는 오류 나면 안되는거니 var keyProperties = _dbContext.Model.FindEntityType(typeof(T)).FindPrimaryKey().Properties; // 각 키 속성에 대해, entity에서 실제 키 값을 추출 var keyValues = keyProperties.Select(p => typeof(T).GetProperty(p.Name).GetValue(entity)).ToArray(); // 기본 키 값을 이용해서 기존 엔티티를 찾음 (복합 키도 자동으로 처리됨) var existingEntity = await _dbContext.Set().FindAsync(keyValues); if (existingEntity != null) { _logger.LogInformation($"[{typeof(T)}] 기존 데이터 발견: 기본 키 값({string.Join(", ", keyValues)})"); // 기존 엔티티를 업데이트: 새 entity의 값으로 교체 _dbContext.Entry(existingEntity).CurrentValues.SetValues(entity); } else { _logger.LogInformation($"[{typeof(T)}] 신규 데이터 등록: 기본 키 값({string.Join(", ", keyValues)})"); // 데이터가 없으면 새 엔티티 추가 _dbContext.Set().Add(entity); } } await _dbContext.SaveChangesAsync(); _logger.LogInformation($"[{typeof(T)}] DB 저장 완료: 종료"); return true; } catch (Exception ex) { _logger.LogInformation($"[{typeof(T)}] 저장 중 알 수 없는 오류 발생: {ex}"); return false; } } public async Task DeleteData(T entity, Expression> key = null) where T : class { try { if (key != null) { // key를 통해 조건식을 만들어 삭제할 엔티티를 찾는 경우 var value = key.Compile()(entity); var parameter = Expression.Parameter(typeof(T), "x"); var invokedExpr = Expression.Invoke(key, parameter); var constantExpr = Expression.Constant(value, key.Body.Type); var equalsExpr = Expression.Equal(invokedExpr, constantExpr); var predicate = Expression.Lambda>(equalsExpr, parameter); var entityData = await _dbContext.Set().FirstOrDefaultAsync(predicate); if (entityData == null) { _logger.LogInformation($"[{typeof(T)}] 삭제 대상 데이터가 존재하지 않습니다. (값 = {value})"); return false; } _logger.LogInformation($"[{typeof(T)}] 조건에 맞는 데이터 발견 (값 = {value}): 삭제 진행"); _dbContext.Set().Remove(entityData); } else { // key가 없는 경우 EF Core 메타데이터를 사용하여 기본 키를 통한 삭제 var entityType = _dbContext.Model.FindEntityType(typeof(T)); if (entityType == null) { throw new InvalidOperationException($"Entity type '{typeof(T).Name}'이 모델에 존재하지 않습니다."); } var primaryKey = entityType.FindPrimaryKey(); if (primaryKey == null) { throw new InvalidOperationException($"Entity type '{typeof(T).Name}'에 기본 키가 정의되어 있지 않습니다."); } var keyProperties = primaryKey.Properties; var keyValues = keyProperties.Select(p => typeof(T).GetProperty(p.Name).GetValue(entity)).ToArray(); var existingEntity = await _dbContext.Set().FindAsync(keyValues); if (existingEntity == null) { _logger.LogInformation($"[{typeof(T)}] 기본 키 값({string.Join(", ", keyValues)})에 해당하는 삭제 대상 데이터가 존재하지 않습니다."); return false; } _logger.LogInformation($"[{typeof(T)}] 기본 키 값({string.Join(", ", keyValues)})에 해당하는 데이터 발견: 삭제 진행"); _dbContext.Set().Remove(existingEntity); } await _dbContext.SaveChangesAsync(); _logger.LogInformation($"[{typeof(T)}] DB에서 삭제 완료"); return true; } catch (Exception ex) { _logger.LogError($"[{typeof(T)}] 삭제 중 오류 발생: {ex}"); return false; } } public string ReadSummary(Type type, string name) { var method = type.GetMethod(name) ?? throw new OutNULLException("swagger summary Load ERROR: NULL"); var att = method.GetCustomAttribute() ?? throw new OutNULLException("swagger summary Load ERROR: NULL"); return att.Summary; } } }