diff --git a/Program/V1/Controllers/UserController.cs b/Program/V1/Controllers/UserController.cs index 42a0ad5..eba1297 100644 --- a/Program/V1/Controllers/UserController.cs +++ b/Program/V1/Controllers/UserController.cs @@ -114,7 +114,8 @@ public class UserController : ControllerBase var refreshToken = _jwtTokenService.GenerateRefreshToken(uid); _logger.LogInformation($"{uid}: {accessToken}, {refreshToken}"); - await _repositoryService.SaveData(refreshToken, rt => rt.uid); + // await _repositoryService.SaveData(refreshToken, rt => rt.uid); + await _repositoryService.SaveData(refreshToken); return Ok(APIResponse.Send("000","정상", new { @@ -236,17 +237,18 @@ public class UserController : ControllerBase }; - if (await _repositoryService.SaveData(user, u => u.uid)) + if (await _repositoryService.SaveData(user)) { - await _repositoryService.SaveData(login, l => l.sns_id); - await _repositoryService.SaveData(permission, p => p.uid); - await _repositoryService.SaveData(contact, c => c.uid); + await _repositoryService.SaveData(login); + await _repositoryService.SaveData(permission); + await _repositoryService.SaveData(contact); } // TO-DO: jwt 토큰 만들어서 여기서 보내는 작업을 해야 함 var token = _jwtTokenService.GenerateJwtToken(uid); var refreshToken = _jwtTokenService.GenerateRefreshToken(uid); - await _repositoryService.SaveData(refreshToken, rt => rt.uid); + + await _repositoryService.SaveData(refreshToken); return Ok(APIResponse.Send("000","정상",new { @@ -268,7 +270,7 @@ public class UserController : ControllerBase if (refreshToken != null) { refreshToken.revoke_Date = DateTime.Now; - await _repositoryService.SaveData(refreshToken, rt => rt.uid); + await _repositoryService.SaveData(refreshToken); return Ok(APIResponse.Send("000", "로그아웃 정상", Empty)); } else diff --git a/Program/V1/Models/AcaException.cs b/Program/V1/Models/AcaException.cs index 3002f2a..c282b34 100644 --- a/Program/V1/Models/AcaException.cs +++ b/Program/V1/Models/AcaException.cs @@ -42,6 +42,7 @@ public class FileContentNotFoundException : Exception { } } + /// /// 외부 서비스에 연결시 연결 실패시 /// @@ -61,5 +62,15 @@ public class PushInvalidException : Exception public PushInvalidException(string message) : base(message) { + } +} +/// +/// 값이 있어야 하는데 NULL인 경우 +/// +public class OutNULLException : Exception +{ + public OutNULLException(string message) : base(message) + { + } } \ No newline at end of file diff --git a/Program/V1/Services/RepositoryService.cs b/Program/V1/Services/RepositoryService.cs index b71dc28..d4940ac 100644 --- a/Program/V1/Services/RepositoryService.cs +++ b/Program/V1/Services/RepositoryService.cs @@ -5,19 +5,23 @@ using AcaMate.Common.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using System.Linq.Expressions; -using System.Security.Claims; -using AcaMate.V1.Models; using Microsoft.IdentityModel.Tokens; using Microsoft.VisualBasic; +using System.Linq.Expressions; +using System.Security.Claims; +using System.Reflection; + +using AcaMate.V1.Models; + namespace AcaMate.V1.Services; public interface IRepositoryService { - Task SaveData(T entity, Expression> key) where T : class; Task ValidateToken(string token, string refresh); - Task SaveDataFK(T entity) where T : class; + 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 @@ -32,58 +36,6 @@ public class RepositoryService: IRepositoryService _logger = logger; _jwtTokenService = jwtTokenService; } - - public async Task SaveData (T entity, Expression> key) where T : class - { - try - { - var value = key.Compile()(entity); - - // x 라 함은 Expression 으로 생성되는 트리에서 T 타입으의 매개변수를 지칭함 - 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 dbSet = _dbContext.Set(); - - var entityData = await dbSet.FirstOrDefaultAsync(predicate); - - if (entityData != null) - { - _logger.LogInformation($"[{typeof(T)}] 해당 PK 존재 [{value}]: 계속"); - var entry = _dbContext.Entry(entityData); - entry.CurrentValues.SetValues(entity); - if (entry.Properties.Any(p => p.IsModified)) - { - _logger.LogInformation($"[{typeof(T)}] 변경사항 존재: 계속"); - } - else - { - _logger.LogInformation($"[{typeof(T)}] 변경사항 없음: 종료"); - return true; - } - } - else - { - _logger.LogInformation($"[{typeof(T)}] 처음등록"); - dbSet.Add(entity); - } - - await _dbContext.SaveChangesAsync(); - _logger.LogInformation($"[{typeof(T)}] DB 저장 완료: 종료"); - return true; - } - catch (Exception ex) - { - _logger.LogInformation($"[{typeof(T)}] 알 수 없는 오류: 종료 {ex}"); - return false; - } - } - //토큰 태울때는 인코딩 된 걸로 태워야지 원본꺼 태우면 데이터에 손상옵니다. /// /// 실제로 엑세스 토큰과 리프레시 토큰으로 접근 하기 위한 메서드 @@ -131,7 +83,7 @@ public class RepositoryService: IRepositoryService { refreshToken = _jwtTokenService.GenerateRefreshToken(uid); _logger.LogInformation("리프레시 토큰 만료"); - await SaveData(refreshToken, rt => rt.uid); + // await SaveData(refreshToken, rt => rt.uid); return new ValidateToken { token = token, @@ -142,53 +94,146 @@ public class RepositoryService: IRepositoryService } } - // public async Task SaveData(T pushCabinet) - // { - // throw new NotImplementedException(); - // } - - - public async Task SaveDataFK(T entity) where T : class + public async Task SaveData(T entity, Expression> key = null) where T : class { try { - // EF Core 메타데이터를 통해 엔티티 T의 기본 키 속성 정보를 가져옴 - 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) + if (key != null) { - _logger.LogInformation($"[{typeof(T)}] 기존 데이터 발견: 기본 키 값({string.Join(", ", keyValues)})"); - // 기존 엔티티를 업데이트: 새 entity의 값으로 교체 - _dbContext.Entry(existingEntity).CurrentValues.SetValues(entity); + // 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 { - _logger.LogInformation($"[{typeof(T)}] 신규 데이터 등록: 기본 키 값({string.Join(", ", keyValues)})"); - // 데이터가 없으면 새 엔티티 추가 - _dbContext.Set().Add(entity); - } + // 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 저장 완료"); + _logger.LogInformation($"[{typeof(T)}] DB 저장 완료: 종료"); return true; } catch (Exception ex) { - _logger.LogError($"[{typeof(T)}] 저장 중 오류 발생: {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); + } - -} \ No newline at end of file + 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; + } +}