fix: 실시간 데이터 반영 완료 - #68
Conversation
Walkthrough플레이어 식별자를 code에서 fplId로 전환하고 이에 맞춰 리포지토리/스케줄러 로직을 수정했다. 라이브 피처 흐름은 LiveFixtureDto에서 FplFixture로 교체되었고, 관련 DTO/서비스/엔티티 메서드 시그니처가 업데이트되었다. 일부 필드 매핑과 불리언 컬럼(nullable→false) 및 JSON 프로퍼티명이 조정되었다. Changes
Sequence Diagram(s)sequenceDiagram
participant Scheduler as DataUpdaterService
participant Repo as PlayerRepository
participant DB as Database
Scheduler->>Repo: findAllByFplIdIn(fplIds)
Repo-->>Scheduler: List<Player>
Scheduler->>Scheduler: 기존 플레이어 맵(키: fplId) 구성
Scheduler->>Repo: markDeletedByFplIdNotIn(fplIds)
Scheduler->>DB: 신규 Player 배치 생성(saveAll)
DB-->>Scheduler: 저장 완료
sequenceDiagram
participant Live as LiveDataService
participant API as FPL API
participant Fix as Fixture(엔티티)
Live->>API: fetchLiveFixtures() -> List<FplFixture>
Live->>Live: hasNoActiveFixtures(fixtures)?
alt 변경사항 있음
Live->>Fix: updateLiveFixture(FplFixture)
end
Live->>API: fetchLiveData()
Live->>Live: processPlayerEvents(liveData, fixtures)<br/>(activeFixtureIds by fplId)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 4
🔭 Outside diff range comments (5)
backendProject/src/main/java/likelion/mlb/backendProject/domain/player/entity/Player.java (1)
140-149: 선수 사진 URL의 opta_code ‘p’ 접두어 누락 및 news 컬럼 null 안전성 보완 필요
- 사진 URL 구성에서
p접두어가 누락되어 있어 이미지 404 가능성이 큽니다. 코드 상단 주석(“opta_code는 p + code”)과도 불일치합니다.news컬럼은 DB에서 nullable=false인데, 외부 API가 null을 줄 경우 제약 위반 위험이 있습니다. 빈 문자열로 폴백하세요.아래처럼 수정 제안드립니다.
- String picUri = "https://resources.premierleague.com/premierleague25/photos/players/110x140/" - + element.getCode() + ".png"; + String picUri = "https://resources.premierleague.com/premierleague25/photos/players/110x140/p" + + element.getCode() + ".png"; this.pic = picUri; this.code = element.getCode(); this.status = element.getStatus(); this.fplId = element.getFplId(); - this.news = element.getNews(); + this.news = element.getNews() != null ? element.getNews() : ""; this.teamCode = element.getTeamCode(); this.chanceOfPlayingNextRound = element.isChanceOfPlayingNextRound(); this.chanceOfPlayingThisRound = element.isChanceOfPlayingThisRound();추가로, 동일한 URL 규칙을 사용하는
playerBuilder(FplElement, ...)의 라인 117-124에도 동일한 접두어(p) 적용 검토를 권장합니다.backendProject/src/main/java/likelion/mlb/backendProject/domain/player/entity/live/PlayerFixtureStat.java (1)
63-118: NPE 위험: Integer 필드 비교에서 오토언박싱 사용 금지
this.minutes != element.getStats().getMinutes()와 같은 비교는 null이 들어오면 NPE가 발생합니다. 라이브 데이터 스트림에 null이 흔해 치명적입니다.Objects.equals(a, b)로 비교 후 변경 시 대입하는 패턴으로 전환하세요.예시 수정안(패턴 적용):
@@ - // 모든 스탯 필드 업데이트 체크 - if (this.minutes != element.getStats().getMinutes()) { - this.minutes = element.getStats().getMinutes(); - hasChanges = true; - } + // 모든 스탯 필드 업데이트 체크 (null-세이프) + var s = element.getStats(); + if (!java.util.Objects.equals(this.minutes, s.getMinutes())) { + this.minutes = s.getMinutes(); + hasChanges = true; + } - if (this.goalsScored != element.getStats().getGoalsScored()) { - this.goalsScored = element.getStats().getGoalsScored(); + if (!java.util.Objects.equals(this.goalsScored, s.getGoalsScored())) { + this.goalsScored = s.getGoalsScored(); hasChanges = true; } - if (this.assists != element.getStats().getAssists()) { - this.assists = element.getStats().getAssists(); + if (!java.util.Objects.equals(this.assists, s.getAssists())) { + this.assists = s.getAssists(); hasChanges = true; } - if (this.cleanSheets != element.getStats().getCleanSheets()) { - this.cleanSheets = element.getStats().getCleanSheets(); + if (!java.util.Objects.equals(this.cleanSheets, s.getCleanSheets())) { + this.cleanSheets = s.getCleanSheets(); hasChanges = true; } - if (this.goalsConceded != element.getStats().getGoalsConceded()) { - this.goalsConceded = element.getStats().getGoalsConceded(); + if (!java.util.Objects.equals(this.goalsConceded, s.getGoalsConceded())) { + this.goalsConceded = s.getGoalsConceded(); hasChanges = true; } - if (this.ownGoals != element.getStats().getOwnGoals()) { - this.ownGoals = element.getStats().getOwnGoals(); + if (!java.util.Objects.equals(this.ownGoals, s.getOwnGoals())) { + this.ownGoals = s.getOwnGoals(); hasChanges = true; } - if (this.penaltiesSaved != element.getStats().getPenaltiesSaved()) { - this.penaltiesSaved = element.getStats().getPenaltiesSaved(); + if (!java.util.Objects.equals(this.penaltiesSaved, s.getPenaltiesSaved())) { + this.penaltiesSaved = s.getPenaltiesSaved(); hasChanges = true; } - if (this.penaltiesMissed != element.getStats().getPenaltiesMissed()) { - this.penaltiesMissed = element.getStats().getPenaltiesMissed(); + if (!java.util.Objects.equals(this.penaltiesMissed, s.getPenaltiesMissed())) { + this.penaltiesMissed = s.getPenaltiesMissed(); hasChanges = true; } - if (this.yellowCards != element.getStats().getYellowCards()) { - this.yellowCards = element.getStats().getYellowCards(); + if (!java.util.Objects.equals(this.yellowCards, s.getYellowCards())) { + this.yellowCards = s.getYellowCards(); hasChanges = true; } - if (this.redCards != element.getStats().getRedCards()) { - this.redCards = element.getStats().getRedCards(); + if (!java.util.Objects.equals(this.redCards, s.getRedCards())) { + this.redCards = s.getRedCards(); hasChanges = true; } - if (this.saves != element.getStats().getSaves()) { - this.saves = element.getStats().getSaves(); + if (!java.util.Objects.equals(this.saves, s.getSaves())) { + this.saves = s.getSaves(); hasChanges = true; } - if (this.bonus != element.getStats().getBonus()) { - this.bonus = element.getStats().getBonus(); + if (!java.util.Objects.equals(this.bonus, s.getBonus())) { + this.bonus = s.getBonus(); hasChanges = true; } - if (this.totalPoints != element.getStats().getTotalPoints()) { - this.totalPoints = element.getStats().getTotalPoints(); + if (!java.util.Objects.equals(this.totalPoints, s.getTotalPoints())) { + this.totalPoints = s.getTotalPoints(); hasChanges = true; }참고:
import java.util.Objects;가 필요합니다.backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveEventDto.java (1)
3-16: LiveFixtureDto 레거시 참조 제거 및 fixtures JSON 역직렬화 확인아래 파일들에서 여전히
LiveFixtureDto를 참조하고 있으므로,FplFixture로 교체해주세요:
- backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/LiveDataService.java
- backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/LiveDataScheduler.java
- backendProject/src/main/java/likelion/mlb/backendProject/domain/round/entity/Fixture.java
예시 수정(diff):
-import likelion.mlb.backendProject.global.staticdata.dto.live.LiveFixtureDto; +import likelion.mlb.backendProject.global.staticdata.dto.fixture.FplFixture;또한, 외부 JSON의
fixtures배열이FplFixture의 필드(team, score, minutes, kickoff_time)와 정확히 매핑되는지 최종 점검 부탁드립니다.backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/LiveDataService.java (2)
271-274: NPE 가능성: Fixture.minutes가 null일 때 언박싱
stat.getFixture().getMinutes()가 Integer일 경우 null 언박싱으로 NPE 발생합니다. 기본값 처리로 방어하세요.- int currentMatchMinute = stat.getFixture().getMinutes(); + Integer minuteObj = stat.getFixture().getMinutes(); + int currentMatchMinute = minuteObj == null ? 0 : minuteObj;
296-299: NPE 가능성(초기 이벤트): Fixture.minutes null 처리 필요초기 이벤트 생성 루틴도 동일한 NPE 위험이 있습니다. 동일한 방식을 적용하세요.
- int currentMatchMinute = stat.getFixture().getMinutes(); + Integer minuteObj = stat.getFixture().getMinutes(); + int currentMatchMinute = minuteObj == null ? 0 : minuteObj;
🧹 Nitpick comments (6)
backendProject/src/main/java/likelion/mlb/backendProject/domain/player/entity/Player.java (1)
36-38: fplId 컬럼 nullable=true 유지가 의도인지 확인 필요PR 전반이 fplId 중심으로 정규화되는 흐름인데, 엔티티에서는
@Column(nullable = true)로 되어 있습니다. 신규/갱신 로직에서 fplId가 항상 채워지는 것이 전제라면, 스키마를 NOT NULL(+ UNIQUE 인덱스)로 강화하는 방안 검토 바랍니다. 마이그레이션 영향도가 있으니 단계적 적용을 추천합니다.backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/DataUpdaterService.java (1)
107-111: 중복 스트림 변환 대신 레포 헬퍼 사용으로 단순화 제안existingMap 구성은 레포지토리의
findAllByFplIdInAsMap을 사용하면 가독성과 비용을 줄일 수 있습니다.적용 예:
- List<Player> existingPlayers = playerRepository.findAllByFplIdIn(allFplIds); - Map<Integer, Player> existingMap = existingPlayers.stream() - .collect(Collectors.toMap(Player::getFplId, Function.identity())); + Map<Integer, Player> existingMap = playerRepository.findAllByFplIdInAsMap(allFplIds);backendProject/src/main/java/likelion/mlb/backendProject/domain/player/repository/PlayerRepository.java (2)
25-25: 파라미터 명칭 정합성 (가독성)
codes대신fplIds가 의도를 더 잘 드러냅니다. 구현엔 영향 없지만 통일을 권장합니다.- List<Player> findAllByFplIdIn(List<Integer> codes); + List<Player> findAllByFplIdIn(List<Integer> fplIds);
41-43: 주석 처리된 죽은 코드 정리 제안주석으로 남긴 대안 쿼리는 혼란만 가중시킵니다. 삭제를 권장합니다.
-// @Query("SELECT p FROM Player p WHERE p.fplId IN :ids") -// List<Player> findAllByFplIdIn(@Param("ids") List<Integer> ids);backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/LiveDataService.java (2)
122-129: 주석 처리된 과거 비교 로직 제거 제안이전 비교 구현 주석은 유지할 이유가 없어 보입니다. 현재
hasFixtureChanged가 더 안전합니다. 주석 제거로 가독성 개선을 권장합니다.
208-213: 메서드 매개변수 명 명확화 (가독성)
getActiveFixtureIds(List<FplFixture> liveData)의 매개변수명이liveData로 되어 있어 혼동됩니다.fixtures로 변경을 제안합니다.- private List<Integer> getActiveFixtureIds(List<FplFixture> liveData) { - return liveData.stream() + private List<Integer> getActiveFixtureIds(List<FplFixture> fixtures) { + return fixtures.stream() .filter(fixture -> fixture.isStarted() && !fixture.isFinished()) .map(FplFixture::getFplId) .toList(); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
backendProject/src/main/java/likelion/mlb/backendProject/domain/player/entity/Player.java(1 hunks)backendProject/src/main/java/likelion/mlb/backendProject/domain/player/entity/live/PlayerFixtureStat.java(1 hunks)backendProject/src/main/java/likelion/mlb/backendProject/domain/player/repository/PlayerRepository.java(1 hunks)backendProject/src/main/java/likelion/mlb/backendProject/domain/round/entity/Fixture.java(1 hunks)backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/DataUpdaterService.java(1 hunks)backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/LiveDataService.java(7 hunks)backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveElementDto.java(1 hunks)backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveEventDto.java(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveEventDto.java (2)
backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/fixture/FplFixture.java (1)
Getter(9-39)backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveFixtureDto.java (1)
Getter(6-31)
backendProject/src/main/java/likelion/mlb/backendProject/domain/player/entity/Player.java (2)
backendProject/src/main/java/likelion/mlb/backendProject/domain/team/entity/Team.java (1)
updateStats(89-99)backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/bootstrap/FplElement.java (1)
Getter(7-49)
backendProject/src/main/java/likelion/mlb/backendProject/domain/player/entity/live/PlayerFixtureStat.java (2)
backendProject/src/main/java/likelion/mlb/backendProject/domain/team/entity/Team.java (1)
Entity(16-100)backendProject/src/main/java/likelion/mlb/backendProject/domain/player/repository/PlayerFixtureStatRepository.java (2)
Repository(14-32)EntityGraph(25-31)
backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveElementDto.java (1)
backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveFixtureDto.java (1)
Getter(6-31)
backendProject/src/main/java/likelion/mlb/backendProject/domain/round/entity/Fixture.java (2)
backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/fixture/FplFixture.java (1)
Getter(9-39)backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveFixtureDto.java (1)
Getter(6-31)
backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/LiveDataService.java (2)
backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/fixture/FplFixture.java (1)
Getter(9-39)backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveFixtureDto.java (1)
Getter(6-31)
backendProject/src/main/java/likelion/mlb/backendProject/domain/player/repository/PlayerRepository.java (1)
backendProject/src/main/java/likelion/mlb/backendProject/domain/player/repository/PlayerFixtureStatRepository.java (1)
Repository(14-32)
🔇 Additional comments (12)
backendProject/src/main/java/likelion/mlb/backendProject/domain/player/entity/Player.java (1)
143-143: code 동기화 추가는 방향성 맞습니다실시간/정기 업데이트 시
code를 최신 FPL 데이터와 동기화하는 것은 일관성 측면에서 타당합니다.backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveElementDto.java (2)
13-14: playerId의 JsonProperty를 "element" → "id"로 변경: 맵핑 일치 👍실제 FPL live elements의 식별자가
"id"로 오는 형태와 정합적입니다. 파이프라인 나머지 구간에서도 해당 변경에 맞춰 참조가 업데이트되었는지만 확인하면 됩니다.
13-14: 호환성 체크 권장: 기존 소스에서 "element" 키 사용 여부이 변경으로 과거 응답 포맷("element")을 기대하던 디시리얼라이즈가 깨지지 않는지 확인 필요합니다. 다중 소스(예: 캐시/히스토릭 파일)에서 들어올 가능성이 있다면 fallback 전략을 고려하세요.
backendProject/src/main/java/likelion/mlb/backendProject/domain/player/entity/live/PlayerFixtureStat.java (2)
41-43: inDreamteam primitive + non-null 컬럼 전환 좋습니다엔티티/DB 제약 일관성이 좋아졌습니다. 기본값 false도 적절합니다.
41-43: 스키마 마이그레이션 점검 필요DB에 기존 null 값이 존재한다면 컬럼을 NOT NULL로 바꾸는 과정에서 에러가 납니다. DDL 변경 전에
UPDATE ... SET in_dreamteam = false WHERE in_dreamteam IS NULL같은 정합성 보정이 필요합니다.backendProject/src/main/java/likelion/mlb/backendProject/global/staticdata/dto/live/LiveEventDto.java (1)
3-16: fixtures를 FplFixture로 교체한 점 일관성 좋습니다라이브 파이프라인 전반에서 FplFixture로 통일하려는 PR 방향성과 부합합니다.
backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/DataUpdaterService.java (2)
103-106: FplId 전환 반영 👍DTO 수집 키를 fplId로 전환한 부분 문제 없습니다. 전체 흐름과 레포지토리 시그니처 변경과도 일관적입니다.
120-128: 업서트 경로 일관성 확보 완료기존/신규 선수 분기에서 fplId 기준 매핑 및 빌더 사용 흐름 깔끔합니다. 도메인 불변조건만 유지되면 문제 없어 보입니다.
backendProject/src/main/java/likelion/mlb/backendProject/domain/player/repository/PlayerRepository.java (2)
26-32: fplId 기준 단건 조회 쿼리 전환 LGTM
JOIN FETCH p.team포함한 fplId 비교로의 전환 적절합니다.
44-47: 헬퍼 메서드로 Map 반환 제공 적절다건 조회 후 Map 변환을 공용화한 접근 좋습니다. 서비스에서 적극 사용 권장합니다.
backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/LiveDataService.java (2)
102-117: 라이브 경기 업데이트 흐름 적절fplId 기반 매핑, 변경 감지 후 업데이트, 상세 로그 모두 적절합니다. 성능 측면에서도 배치 조회(Map) 접근이 좋습니다.
129-143: null-safe 변경 감지 구현 좋습니다minutes 기본값 처리와 Objects.equals 기반 비교로 NPE 가능성을 제거했습니다. 이 방식 유지에 동의합니다.
| @Query("UPDATE Player p SET p.status = 'x' WHERE p.fplId NOT IN :fplIds") | ||
| void markDeletedByFplIdNotIn(@Param("fplIds") List<Integer> fplIds); |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
빈 컬렉션 처리 없는 NOT IN 업데이트 쿼리 — 안전장치 필요
p.fplId NOT IN :fplIds에서 :fplIds가 빈 경우 방언에 따라 전행 업데이트 위험 또는 쿼리 오류가 발생합니다. 서비스 레벨에서 빈 리스트 가드를 강제하세요. (DataUpdaterService에 가드 추가 제안 드렸습니다)
레거시 코드가 남아 있을 수 있으니, 오래된 메서드 호출이 없는지 확인해 주세요:
🏁 Script executed:
#!/bin/bash
# 이전 코드 기반 메서드 호출 잔존 여부 점검
rg -n -C2 -g '!**/build/**' -g '!**/out/**' -S -tjava $'findAllByCodeIn|markDeletedByCodeNotIn'Length of output: 96
기존 스크립트가 잘못된 메서드명을 검색해 빈 결과를 반환했습니다. 실제 메서드명(markDeletedByFplIdNotIn, findAllByFplIdIn)에 대해 호출 잔존 여부를 재확인합니다.
🏁 Script executed:
#!/bin/bash
# fplId 기반 메서드 호출 잔존 여부 점검
rg -n -C2 -g '!**/build/**' -g '!**/out/**' -S -tjava 'markDeletedByFplIdNotIn|findAllByFplIdIn'Length of output: 9751
빈 리스트에 의한 NOT IN 업데이트 쿼리 안전장치 추가 필요
PlayerRepository.markDeletedByFplIdNotIn(List<Integer> fplIds)는 DataUpdaterService에서 단 한 곳(…/DataUpdaterService.java:113)에서만 호출되고 있습니다.
:fplIds가 빈 컬렉션일 때 방언에 따라 전체 행이 삭제되거나 쿼리 오류가 발생할 수 있으므로, 호출 직전에 빈 리스트인 경우 조기 종료 로직을 추가해주세요.
- 파일:
‑ backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/DataUpdaterService.java
‑ 라인: 113 (playerRepository.markDeletedByFplIdNotIn(allFplIds);) - 제안 코드 스니펫:
if (allFplIds.isEmpty()) { // 삭제 대상 없음 return; } playerRepository.markDeletedByFplIdNotIn(allFplIds);
🤖 Prompt for AI Agents
In
backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/DataUpdaterService.java
around line 113, the call to playerRepository.markDeletedByFplIdNotIn(allFplIds)
must be guarded against an empty collection because some SQL dialects treat NOT
IN with an empty list as dangerous (affecting all rows or throwing); add an
early return when allFplIds.isEmpty() (i.e., if empty, log or comment “삭제 대상 없음”
and return) so the repository method is only invoked with a non-empty list.
| public void updateLiveFixture(FplFixture dto) { | ||
| this.started = dto.isStarted(); | ||
| this.finished = dto.isFinished(); | ||
| this.homeTeamScore = dto.getHomeTeamScore(); | ||
| this.awayTeamScore = dto.getAwayTeamScore(); | ||
| this.minutes = dto.getMinutes(); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
minutes 컬럼(nullable=false)에 null 대입 가능성 — 방어 로직 필요
외부 응답에서 minutes가 null일 수 있습니다. 현재 그대로 대입하면 JPA flush 시 제약 위반 위험이 있습니다. 이전 값을 유지하거나 0으로 폴백하세요. 이전 값 유지가 안전합니다.
public void updateLiveFixture(FplFixture dto) {
this.started = dto.isStarted();
this.finished = dto.isFinished();
this.homeTeamScore = dto.getHomeTeamScore();
this.awayTeamScore = dto.getAwayTeamScore();
- this.minutes = dto.getMinutes();
+ this.minutes = dto.getMinutes() != null ? dto.getMinutes() : this.minutes;
}🤖 Prompt for AI Agents
In
backendProject/src/main/java/likelion/mlb/backendProject/domain/round/entity/Fixture.java
around lines 117 to 123, the updateLiveFixture method assigns dto.getMinutes()
directly but the minutes column is non-nullable and external responses may
return null; change the assignment to guard against null by only overwriting
this.minutes when dto.getMinutes() != null (otherwise preserve the existing
value), so the entity never gets a null minutes value (alternatively fall back
to 0 if you prefer explicit default).
|
|
||
| // 3) 삭제 처리 (DB에 남아있으나 allCodes 에 없는 선수들) | ||
| playerRepository.markDeletedByCodeNotIn(allCodes); | ||
| playerRepository.markDeletedByFplIdNotIn(allFplIds); |
There was a problem hiding this comment.
빈 목록 전달 시 대량 업데이트 위험 (NOT IN 빈 컬렉션)
markDeletedByFplIdNotIn(allFplIds) 호출 시, allFplIds가 빈 리스트면 JPA 구현체/DB 방언에 따라 전행 업데이트가 발생하거나 쿼리 오류가 날 수 있습니다. 외부 API 장애 등으로 elements가 비어올 경우를 방어해야 합니다.
서비스 레벨에서 빈 리스트 가드 추가를 권장합니다.
- playerRepository.markDeletedByFplIdNotIn(allFplIds);
+ if (!allFplIds.isEmpty()) {
+ playerRepository.markDeletedByFplIdNotIn(allFplIds);
+ } else {
+ log.warn("elements가 비어있어 삭제 마킹을 건너뜁니다. (외부 API 점검/오류 가능성)");
+ }또는 레포지토리 측에 별도 안전 쿼리 메서드 추가가 가능합니다. 필요 시 패치 제안 드리겠습니다.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| playerRepository.markDeletedByFplIdNotIn(allFplIds); | |
| // 빈 목록 전달 시 전행 업데이트/오류 방어 | |
| if (!allFplIds.isEmpty()) { | |
| playerRepository.markDeletedByFplIdNotIn(allFplIds); | |
| } else { | |
| log.warn("elements가 비어있어 삭제 마킹을 건너뜁니다. (외부 API 점검/오류 가능성)"); | |
| } |
🤖 Prompt for AI Agents
In
backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/DataUpdaterService.java
around line 113, calling playerRepository.markDeletedByFplIdNotIn(allFplIds)
without checking for an empty collection can trigger a full-table update or SQL
error when allFplIds is empty; add a guard that checks if allFplIds is null or
empty and skip the repository call (optionally log a warning) or implement/use a
repository method that safely ignores empty input (e.g.,
markDeletedByFplIdNotInIfNotEmpty) so we never pass an empty collection to a NOT
IN query.
| private boolean hasNoActiveFixtures(List<FplFixture> fixtures) { | ||
| if (fixtures == null || fixtures.isEmpty()) return true; | ||
| return fixtures.stream().noneMatch(f -> | ||
| Boolean.TRUE.equals(f.isStarted()) || (f.getMinutes() != null && f.getMinutes() > 0)); | ||
| } |
There was a problem hiding this comment.
종료된 경기까지 ‘활성’으로 오판 가능 — 활성 판단 로직 불일치
hasNoActiveFixtures는 started == true만으로 활성로 간주합니다. 종료(finished == true)인 경기도 started는 true라 계속 활성로 인식됩니다. 아래와 같이 finished 배제를 포함해 getActiveFixtureIds와 기준을 일치시키세요.
- private boolean hasNoActiveFixtures(List<FplFixture> fixtures) {
- if (fixtures == null || fixtures.isEmpty()) return true;
- return fixtures.stream().noneMatch(f ->
- Boolean.TRUE.equals(f.isStarted()) || (f.getMinutes() != null && f.getMinutes() > 0));
- }
+ private boolean hasNoActiveFixtures(List<FplFixture> fixtures) {
+ if (fixtures == null || fixtures.isEmpty()) return true;
+ return fixtures.stream().noneMatch(f ->
+ (f.isStarted() || (f.getMinutes() != null && f.getMinutes() > 0))
+ && !f.isFinished()
+ );
+ }또는 더 단순하게 return getActiveFixtureIds(fixtures).isEmpty();로 통일해도 됩니다.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private boolean hasNoActiveFixtures(List<FplFixture> fixtures) { | |
| if (fixtures == null || fixtures.isEmpty()) return true; | |
| return fixtures.stream().noneMatch(f -> | |
| Boolean.TRUE.equals(f.isStarted()) || (f.getMinutes() != null && f.getMinutes() > 0)); | |
| } | |
| private boolean hasNoActiveFixtures(List<FplFixture> fixtures) { | |
| if (fixtures == null || fixtures.isEmpty()) return true; | |
| return fixtures.stream().noneMatch(f -> | |
| (f.isStarted() || (f.getMinutes() != null && f.getMinutes() > 0)) | |
| && !f.isFinished() | |
| ); | |
| } |
🤖 Prompt for AI Agents
In
backendProject/src/main/java/likelion/mlb/backendProject/global/scheduler/service/LiveDataService.java
around lines 83 to 87, the hasNoActiveFixtures method treats fixtures with
started == true as active even if finished == true, causing inconsistency with
getActiveFixtureIds; update the logic to exclude fixtures where finished == true
(mirror the active criteria used in getActiveFixtureIds) or replace the method
body with a call to getActiveFixtureIds(fixtures).isEmpty() to ensure both use
the same active-definition.
Summary by CodeRabbit
버그 수정
변경
리팩터링