inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

묻고 답해요

173만명의 커뮤니티!! 함께 토론해봐요.

세팅하기 질문입니다.

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

"세팅하기" 강의의 8분에서 meta-data를 넣는데요 pubdev에서 <manifest ... <application ... <meta-data android:name=" com.google.android .geo.API_KEY" android:value="YOUR KEY HERE"/> 이렇게 써져있는데 <application> 이 괄호(<>) 안에 meta-data를 넣으라는 말이 아니라 아래에 넣으라는 말인건가요?

  • flutter
  • 클론코딩
댓글 1 좋아요 0 조회수 376

Sliver 를 사용한 이유.

미해결

[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!

ListView 대신에 Sliver 를 사용하신 이유가 먼가요? 어떤 걸 써도 동일한 효과인가요?

  • flutter
  • 하이브리드-앱
Seung Min Liang 댓글 1 좋아요 0 조회수 501

디바이스별 비율 적용

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

안녕하세요! 너무 좋은 강의 감사합니다. 아이폰, 안드로이드 폰 기기별 사이즈와 비율이 다른데 어떻게하면 기기별 비율에 맞게 맞출 수 있나요? 예를 들어 아이콘 사이즈가 39*39 인데 (디자이너 기준 아이폰 12프로) 아이폰 13미니에서는 아이콘 사이즈, 텍스트 위젯등 모두 비율에 맞게 작아져야하는데 방법을 모르겠습니다.

  • flutter
  • 클론코딩
최용준 댓글 1 좋아요 0 조회수 441

Failed assertion: line 246 pos 15: 'items.length >= 2': is not true.

미해결

Flutter 입문 - 안드로이드, iOS 개발을 한 번에 (with Firebase)

import 'package:flutter/material.dart'; class TabPage extends StatefulWidget { const TabPage({super.key}); @override State<TabPage> createState() => _TabPageState(); } class _TabPageState extends State<TabPage> { @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: BottomNavigationBar( items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'), ], ), ); } } 이 부분에서 코드를 작성한 후 실행하면 ======== Exception caught by widgets library ======================================================= The following assertion was thrown building TabPage(dirty, state: _TabPageState#63dc1): 'package:flutter/src/material/bottom_navigation_bar.dart': Failed assertion: line 246 pos 15: 'items.length >= 2': is not true. The relevant error-causing widget was: TabPage TabPage:file:///C:/Users/user/StudioProjects/instagram/lib/main.dart:21:19 When the exception was thrown, this was the stack: #2 new BottomNavigationBar (package:flutter/src/material/bottom_navigation_bar.dart:246:15) #3 TabPageState.build (package:instagram/tab/tab page.dart:14:28) #4 StatefulElement.build (package:flutter/src/widgets/framework.dart:5409:27) #5 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5297:15) #6 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5462:11) #7 Element.rebuild (package:flutter/src/widgets/framework.dart:5016:7) #8 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:5279:5) #9 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5453:11) #10 ComponentElement.mount (package:flutter/src/widgets/framework.dart:5273:5) ... Normal element mounting (220 frames) #230 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4182:16) #231 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6569:36) #232 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6581:32) ... Normal element mounting (467 frames) #699 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4182:16) #700 Element.updateChild (package:flutter/src/widgets/framework.dart:3707:18) #701 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1253:16) #702 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1222:5) #703 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1169:18) #704 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2719:19) #705 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1168:13) #706 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:1001:7) #707 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:981:7) #711 RawReceivePort. handleMessage (dart:isolate-patch/isolate_patch.dart:189:12) (elided 5 frames from class AssertionError, class Timer, and dart:async-patch) ==================================================================================================== D/ProfileInstaller(12980): Installing profile for com.example.instagram 이런 에러가 계속 발생하는데 어떤 식으로 해결해야 할까요??

  • flutter
  • ios
  • android
etl 댓글 1 좋아요 0 조회수 1345

리스트에 숫자를 넣었더니 . 순서가 뒤죽 박죽으로 나옵니다.

해결됨

Flutter 앱 개발 기초

5강 . 데이터베이스 고쳐서 진행중입니다. 리스트에 숫자를 넣었더니 . 순서가 뒤죽 박죽으로 나옵니다. 정렬되어 나오게 하려면 어떻게 해야하는지 귀뜸좀 주시면 감사하겠습니다. 아래처럼 되어요. 순서대로 orderby 이런게 있는지 궁금합니다. sleep1 sleep4 sleep2 sleep5 sleep sleep3

  • flutter
what? just run 댓글 2 좋아요 1 조회수 412

안녕하세요. hot restart를 하면 _HomeScreenState의 Build 위젯이 두 번 실행되는데 왜 그런거죠?

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

안녕하세요. 이런식으로 build(){}위젯이 몇 번 불리나 확인해봤는데, hot restart하면 우선 기본적으로 두 번 불리는 것 같습니다. 왜 그런 것이죠? 감사합니다!

  • flutter
  • 클론코딩
김남현 댓글 1 좋아요 0 조회수 312

fetchPointTransactionsOfBuying API에서 특정 정보만 불러와지지 않습니다.

해결됨

[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스

안녕하세요 강사님. 마이페이지 내 포인트 화면의 구매내역 조회기능을 구현 중에 있습니다. fetchPointTransactionsOfBuying API 로 구매내역을 조회하는데 판매자의 이름이 불러와지지 않습니다.. const FETCH_POINT_TRANSACTIONS_OF_BUYING = gql` query fetchPointTransactionsOfBuying($search: String, $page: Int) { fetchPointTransactionsOfBuying(search: $search, page: $page) { _id impUid amount balance status statusDetail useditem { _id name price seller { _id # name # email } buyer { _id name email } soldAt } createdAt } } `; useditem.seller._id 까지는 조회가 되는데 name 과 email 은 조회가 되지않습니다. 혹시나 해서 buyer 정보를 불러왔는데 buyer 도 _id 만 조회가 되고 name 과 email 는 조회가 되지 않습니다. 위와 같은 오류가 나오는데 제가 모르는 부분이 있는건지 데이터에 문제가 있는건지 잘 모르겠습니다.. !

  • react
  • node.js
  • seo
  • graphql
  • next.js
summery 댓글 2 좋아요 0 조회수 348

섹션23 미세먼지앱 postman

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

강의대로 다운로드받고, 작성했는데 SEND를 눌러도 그대로이고 MAP값들을 불러오지를 못하네요

  • flutter
  • 클론코딩
MJ90 댓글 3 좋아요 0 조회수 499

5강 파이어베이스 연결하기, 업데이트로 바뀌엇어요. 아시는분?

해결됨

Flutter 앱 개발 기초

5 강 파이어베이스 연결 되시는분 귀뜸좀 해주세요 . 막혀서 진행 못하고 있습니다. 5강 파이어베이스 연결하기 . 안드로이드로 하는데 달라요 . app> build.gradle 에러 throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") gradle>build.gradle 파이어베이스 연결하는게 사이트와 다릅니다. 다른 연결하는 법을 알려 주세요 . android 하고 새로이 바뀐건 또 flutter가 업데이트되었습니다.

  • flutter
what? just run 댓글 1 좋아요 1 조회수 392

토큰 재발급 관련 질문입니다.

해결됨

[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!

안녕하세요. 기초를 수강하고, 중급 강의 절반 정도 수강한 학생입니다. 우선, 기초와 중급 모두 좋은 퀄리티의 영상과 강의를 올려주셔서 정말 감사드린다는 말씀 드립니다! 현재 강의와는 별개로 따로 진행하고 있는 프로젝트에서 한 페이지에 여러 api 호출을 진행하는 과정에서 access 토큰이 만료되었을 때의 상황에서 문제를 겪고 있습니다. 예를 들어, 3개의 api를 호출하여 FutureBuilder 3개 혹은 Future.wait으로 3개의 데이터를 가져오는 상황입니다. 우선, 모든 요청에 access 토큰 만료를 백엔드에서 계산하고 있습니다. 만료가 되었을 때, 프론트로 401이 던져지고 onError에서 이를 캐치하여 재발급 api를 호출하고 다시 토큰을 갱신하여 secure storage에 저장하고 있습니다. (백엔드에서는 access 토큰이 만료되어 재발급 요청을 받으면, 유효한 refresh 토큰인지 확인하여 유효시 두 토큰 모두 갱신하여 재발급해줍니다.) 이 과정에서 3개의 모든 api 요청에 대한 재발급을 시도하여 3번의 재발급 요청이 이루어지게 됩니다. 그리고나서 3개의 모든 api 요청에 다시 resolve를 하게 되는데, 이러한 순서의 로직이 맞는 부분인지 궁금합니다. 어려움을 겪고 있는 부분에는 3개의 요청 중 2개의 요청은 요청된 시간이 밀리세컨드 단위로 다르지만, 재발급 된 토큰이 동일해 요청이 성공적으로 진행됩니다. (5개라면 2개가 성공할 때가 있고, 3개가 성공할 때가 있고 시시각각 변합니다..) 하지만, 남은 api 요청은 앞선 요청에서 이미 새롭게 토큰이 발급되었기 때문에 갱신되지 않은 토큰으로 요청을 보내게 되고, 서버에서는 토큰이 새로 갱신되었기 때문에 토큰이 유효하지 않다는 오류가 발생하게 됩니다. 여러 레퍼런스를 참고하여 QueuedInterceptorsWrapper 및 일부 코드를 추가하여 임시로 해결해놓은 상태이지만, 근본적인 원인 해결이 되지 않았다고 생각하여 질문드립니다. (여전히 5개의 요청이라면, 5개의 재발급 요청을 보내는 상황입니다...) 아직 남은 강의를 모두 들어보지 않아 해결하지 못하는 문제일 수 있지만, 미리 질문부터 드리는 점 양해 드립니다,,ㅠ 서둘러 완강해보도록 하겠습니다! 감사합니다 :)

  • flutter
  • 하이브리드-앱
swiper 댓글 1 좋아요 1 조회수 488

Map 함수로 실전적용!

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

final numbers = [123, 456, 789]; print( numbers.map ((x) => x.toString().split('').map((y) => '$y.jpg', ).toList(), ), ([1.jpg, 2.jpg, 3.jpg], [4.jpg, 5.jpg, 6.jpg], [7.jpg, 8.jpg, 9.jpg]) print( numbers.map ((x) => x.toString().split('').map((y) => '$y.jpg', ), ).toList(), [(1.jpg, 2.jpg, 3.jpg), (4.jpg, 5.jpg, 6.jpg), (7.jpg, 8.jpg, 9.jpg)] 소괄호와 대괄호가 무슨차이죠. 처음에 첫번째 처럼하면 list될것같았는데요. 같은줄 알았는데 다르더라구요. 2번째는 그냥 해본거예요. 무슨차이인지 알고싶어요. final number = 123; print(number.toString().split('')); print(number.toString().split('').map((x)=> '$x.jpg')); [1, 2, 3] (1.jpg, 2.jpg, 3.jpg) 위에는 대괄호, 밑에는 소괄호 괄호가 같는결과는 아니네요.

  • flutter
  • 클론코딩
vadain2000 댓글 1 좋아요 0 조회수 373

goNamed질문

미해결

[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!

GoRoute( path: 'chef/register/two', name: ChefRegisteScreen2.routeName, builder: (_,state) => ChefRegisteScreen2( //rid: 123 ) ), goNamed로 String값 말고 Map이나 리스트 자료형을 넘기는 방법이 있을까요?

  • flutter
  • 하이브리드-앱
dlckdals9467 댓글 1 좋아요 -1 조회수 314

selectedDayPredicate 함수 관련 질문드립니다.

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

selectedDayPredicate에 파라미터로 들어가있는 함수는 DateTime타입의 인자를 필수적으로 받아와야 하는걸로 압니다. 그런데 코드에서 어떤 부분도 이 함수에 인자를 전달해주지 않는데 어떻게 date인자에 날짜들이 들어가있는지, 그렇다면 강의를 보지않았을 때 이 인자가 그런식으로 데이터가 들어있다는것을 어디서 어떻게 확인해야하는 지 궁금합니다.

  • flutter
  • 클론코딩
이우진 댓글 1 좋아요 0 조회수 253

JPA 최적화 강의 수강 후, 개인 프로젝트 수행하면서 생긴 질문입니다.

해결됨

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

안녕하세요. JPA 최적화 강의를 수강하고, 개인적으로 DDD를 책으로 공부해본 후에 개인 토이 프로젝트를 진행하던 중, 뜻밖에 의문이 생겼는데 여쭐 곳이 없어서 이렇게 질문 올리게 되었습니다. 맨 땅에 헤딩으로 이런저런 강의, 책, 다른 분들의 소스를 참고 하려다보니 여러 개념이 뒤섞여서 혼동이 옵니다.. ㅠㅠ 현재 프로젝트에서는 크게 에그리거트를 CUSTOMER, EXTERNAL, SECURITYMEDIA 3개로 나누어 설계했는데요. 강의에서도, 책에서도 DOMAIN 계층에 있는 서비스는 해당 도메인에 대한 순수한 CRUD를 수행하는 것으로 보았습니다. DDD 책에서는 여러 에그리거트가 필요로 하는 기능을 구현할 때는 도메인 서비스로 구현하라고 이야기 했구요. 처음에는 책에서 조언하는 대로 도메인 서비스로 구현해보고자 하다가, 좀처럼 구현이 안되어서 다른 분들이 구현한 소스를 참조하다 보니 application(응용)영역을 FACADE라는 상위 계층을 두는 것을 방식을 알게 되었습니다. 소스를 따라가보니 각 애그리거트의 DOMAIN 영역에 있는 서비스를 주입하여, 각 도메인 영역에 있는 서비스를 적절히 호출하기에 책에서 본 도메인 서비스와 같은 역할을 하겠구나 하여,, 해당 프로젝트 구성 방식을 따라 개발해보기로 했습니다. 그런데 개발을 하다보니,, 참조하는 소스에서 메소드 단위의 트랜잭션의 적용을 facade 영역이 아닌, 도메인 영역의 서비스 구현체에서 하는 것을 알게 되었습니다. 제가 개발하고자 기능은 여러 애그리거트를 생성, 변경하는 하나의 행위가 하나의 트랜잭션으로 묶여야 하는데 말이죠. 이러한 이유 때문에 현재 소스는 FACADE에서는 하나의 도메인 영역의 서비스를 주입하여 하나의 메소드를 호출하도록 되어있고, 도메인 영역에 있는 해당 서비스의 구현체에서 여러 애그리거트의 서비스, 레포지토리를 주입받아 하나의 메소드에서 트랜잭션 단위로 수행하도록 구현되어있습니다.. @Service @RequiredArgsConstructor public class SecurityMediaFacade { private final SecurityMediaService securityMediaService; public SecurityMediaInfo.Main registerOtp(SecurityMediaCommand.RegisterSecurityMediaRequest req) { //디지털otp 발급 // 디지털 otp 발행 return securityMediaService.issueSecurityMedia(req, SecurityMediaType.DIGITAL_OTP); } ... } public interface SecurityMediaService { public SecurityMediaInfo.Main issueSecurityMedia(SecurityMediaCommand.RegisterSecurityMediaRequest req, SecurityMediaType type); ... } @Slf4j @Service @RequiredArgsConstructor public class SecurityMediaServiceImpl implements SecurityMediaService { private final CustomerReader customerReader; private final SecurityMediaStore securityMediaStore; private final TokenStore tokenStore; private final ExternalClientService externalClientService; @Override @Transactional public SecurityMediaInfo.Main issueSecurityMedia(SecurityMediaCommand.RegisterSecurityMediaRequest req, SecurityMediaType type) { // 요청고객 찾기 Customer customer = customerReader.findCustomerByRnn(req.getRnn()); SecurityMedia newOtp = null; if(!customer.existActiveSecurityMedia()) { // otp 신규 SecurityMedia initOtp = req.toEntity(SecurityMediaType.DIGITAL_OTP, customer); newOtp = securityMediaStore.store(initOtp); // 토큰 발급 요청 Token newToken = externalClientService.getToken(customer, newOtp); newOtp.addToken(newToken); tokenStore.store(newToken); } return new SecurityMediaInfo.Main(newOtp); } 위에는 프로젝트의 구성인데.. 첫 단추부터 잘못 끼운 것도 같아서 시작 단계인 지금에서라도 좀 개선을 해보려고 하는데요. 사실 도메인 서비스가 제가 의도로 하는 여러 애그리거트의 서비스 기능을 묶어서 하는 건지 아무리 읽어봐도 혼선이 옵니다. 혹시 DDD 책에서 이벤트라는 개념이 나오는데 도메인 서비스가 아니라, 이 이벤트를 통해 다른 애그리거트의 응용 서비스를 호출하도록 핸들링 하는게 올바른 방법일까요? 지금과 같은 구조를 유지해도 된다면.. facade 영역의 메소드를 트랜잭션으로 묶고, 각 도메인 계층의 서비스들에서 선언된 해당 도메인에 대한 crud 메소드를 적절히 호출해가면서 facade 영역에서 비즈니스 로직을 처리해도 될까요? 너무 글이 장황하고 기네요.. ㅠㅠ 혹시 도움을 주신다면 너무나도 감사드리겠습니다.

  • java
  • spring
  • spring-boot
  • jpa
인생은회전목마 댓글 1 좋아요 0 조회수 510

onDaySelected가 타입이 아니라고 나오네요 그리고

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

안녕하세요. 섹션21 TodayBanner 설계 강좌에서 아래와 같은 에러 메시지가 나와서 더 이상 진행이 안 됩니다. final onDaySelected? onDaySelected; 에서 onDaySelected가 타입이 아니라고 나오네요. 강좌에서 밖으로/위로(?) 빼는 작업과 statefull로 바꾸는 과정에서부터 에러가 나와서 여기서 막혀 더 이상 강의를 따라하며 들을 수 없습니다. 혹시나 해서 소스 코드를 깃허브에 올려 두었습니다. 소스코드는 아래에 있습니다. https://github.com/kooboom/calendar_scheduler lib/component/calendar.dart:12:9: Error: The name of a constructor must match the name of the enclosing class. const Calendar({ ^^^^^^^^ lib/component/calendar.dart:9:9: Error: 'onDaySelected' isn't a type. final onDaySelected? onDaySelected; ^^^^^^^^^^^^^ lib/component/calendar.dart:9:24: Context: This isn't a type. final onDaySelected? onDaySelected; ^^^^^^^^^^^^^ lib/screen/home_screen.dart:28:13: Error: The method 'Calendar' isn't defined for the class '_HomeScreenState'. - '_HomeScreenState' is from 'package:calendar_scheduler/screen/home_screen.dart' ('lib/screen/home_screen.dart'). Try correcting the name to the name of an existing method, or defining a method named 'Calendar'. Calendar( 소스코드는 아래에 있습니다. https://github.com/kooboom/calendar_scheduler

  • flutter
  • 클론코딩
쿠붐 댓글 2 좋아요 0 조회수 450

Drift 패키지의 테이블 이름 질문

해결됨

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

안녕하세요? 캘린더 프로젝트 관련 질문사항이 있습니다. 먼저 drift 패키지를 사용하기 위해 객체를 선언했습니다. - CategoryColors, Schedules 모두 뒤에 s가 붙은 이름으로 테이블을 사용하기 위한 ORM 객체를 선언한것 까지는 알겠는데요. (s 붙이는게 필수?) drift가 자동 생성한 소스에 보면 s가 빠진 클래스들이 생성이 되어 있습니다. - CategoryColor, Schedule 여기에 궁금함이 있습니다. 처음에 객체 선언에 반드시 s를 붙여야 하는 건지? 붙이지 않는다면 어떤 클래스 이름으로 자동 생성이 되는건지? Schedules 클래스 선언 -> (자동생성) Schedule 객체 s 가 빠진 원리를 알고 싶습니다.

  • flutter
  • 클론코딩
archy712 댓글 1 좋아요 0 조회수 326

객체가 스스로의 리스트를 가지고, 양방향 매핑을 해도 될까요?

해결됨

자바 ORM 표준 JPA 프로그래밍 - 기본편

[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? ( 예 /아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? ( 예 /아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? ( 예 /아니오) [질문 내용] 악! 스프링 웹 개발은 즐거워! 김영한 선생님 질문있습니다. 선생님의 두 로드맵을 거의 다 듣고 그를 바탕으로 포폴용 게시판을 만들어보고 있습니다. 와중 댓글과 대댓글 기능을 구현하는 과정에서 Comment라는 객체를 만들고 객체의 타입을 Comment와 reply로 나누었습니다. 특정 게시판에 관한 데이터를 불러올 때 댓글과 대댓글을 편리하게 불러오기 위해 타입이 Comment인 객체가 reply에 해당하는 객체를 리스트로 갖도록 설계했습니다. 이후 테스트를 진행해보았는데 fetch join을 통한 데이터 로드는 문제 없이 진행되었습니다. 다만 이러한 설계 방식이 올바른지에 대한 질문을 스스로 해결할 수 없어서 글 남깁니다. 아래는 코드와 테스트 코드 및 실행 결과이고, 마지막에 질문이 있습니다. package toy.board.domain.post; import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.util.StringUtils; import toy.board.domain.BaseDeleteEntity; import toy.board.domain.user.Member; @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PROTECTED) @EqualsAndHashCode(callSuper = true) public class Comment extends BaseDeleteEntity { public static final int CONTENT_LENGTH = 1000; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "comment_id", nullable = false) private Long id; @Column(name = "content", nullable = false, length = CONTENT_LENGTH) private String content; @Column(name = "type", nullable = false, updatable = false) private CommentType type; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "post_id", nullable = false, updatable = false) private Post post; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id", nullable = false, updatable = false) private Member member; @OneToMany(mappedBy = "parent") private List<Comment> replies = new ArrayList<>(); @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_comment_id", updatable = false) private Comment parent; /** * 양방향 관계인 Member와 Post에 대해 자동으로 양방향 매핑을 수행한다. */ public Comment( @NotNull final Post post, @NotNull final Member member, @NotNull final String content, @NotNull final CommentType type ) { this.post = post; this.member = member; this.content = content; this.type = type; } public boolean update(final String content) { if (!StringUtils.hasText(content)) { return false; } this.content = content; return true; } public void leaveReply(Comment reply) { if (areTypesCorrectThisAnd(reply)) { throw new IllegalArgumentException("주어진 댓글과 대댓글의 타입이 올바르지 않습니다."); } if (hasComment(reply)) { throw new IllegalArgumentException("대댓글이 이미 다른 댓글에 포섭되어 있습니다."); } if (isNew(reply)) { throw new IllegalArgumentException("댓글이 이미 해당 대댓글을 포함하고 있습니다."); } this.replies.add(reply); reply.parent = this; } private boolean isNew(Comment reply) { return this.replies.contains(reply); } private static boolean hasComment(Comment reply) { return reply.parent != null; } private boolean areTypesCorrectThisAnd(Comment reply) { return this.type != CommentType.COMMENT || reply.type != CommentType.REPLY; } } @Transactional @DisplayName("comment가 List<comment>를 갖고, fetch join으로 가져올 수 있는가?") @Test public void comment_has_comments_fetch_join() throws Exception { //given Member member = Member.builder( "member", new Login("password"), Profile.builder("nickname").build(), LoginType.LOCAL_LOGIN, UserRole.USER ).build(); em.persist(member); Post post = new Post(member, "title", "content"); em.persist(post); Comment comment = new Comment(post, member, "comment", CommentType.COMMENT); em.persist(comment); for (int i = 0; i < 5; i++) { Comment reply = new Comment(post, member, "reply" + String.valueOf(i), CommentType.REPLY); comment.leaveReply(reply); em.persist(reply); } em.flush(); em.clear(); //when QComment reply = new QComment("reply"); List<Comment> findComments = queryFactory .selectFrom(QComment.comment) .leftJoin(QComment.comment.replies, reply).fetchJoin() .where( QComment.comment.post.id.eq(post.getId()), QComment.comment.type.eq(CommentType.COMMENT) ) .fetch(); System.out.println("============================================="); for (Comment findComment : findComments) { System.out.println("findComment.getId() = " + findComment.getId()); System.out.println("findComment.getContent() = " + findComment.getContent()); } //then Comment findComment = findComments.get(0); for (Comment findReply : findComment.getReplies()) { System.out.println("findReply content = " + findReply.getContent()); } } [테스트 실행 시 create query] create table comment ( is_deleted boolean default false not null, type tinyint not null check (type between 0 and 1), comment_id bigint generated by default as identity, created_date timestamp(6), deleted_date timestamp(6), last_modified_date timestamp(6), member_id bigint not null, parent_comment_id bigint, post_id bigint not null, content varchar(1000) not null, created_by varchar(255), last_modified_by varchar(255), primary key (comment_id) ) [테스트 실행 결과] select c1_0.comment_id, c1_0.content, c1_0.created_by, c1_0.created_date, c1_0.deleted_date, c1_0.is_deleted, c1_0.last_modified_by, c1_0.last_modified_date, c1_0.member_id, c1_0.parent_comment_id, c1_0.post_id, r1_0.parent_comment_id, r1_0.comment_id, r1_0.content, r1_0.created_by, r1_0.created_date, r1_0.deleted_date, r1_0.is_deleted, r1_0.last_modified_by, r1_0.last_modified_date, r1_0.member_id, r1_0.post_id, r1_0.type, c1_0.type from comment c1_0 left join comment r1_0 on c1_0.comment_id=r1_0.parent_comment_id where c1_0.post_id=? and c1_0.type=? ===================== findComment.getId() = 1 findComment.getContent() = comment findReply content = reply0 findReply content = reply1 findReply content = reply2 findReply content = reply3 findReply content = reply4 [질문] 제가 궁금한 것을 자세히 말하자면, 테이블이 만들어질 때, comment 테이블의 특정 row(대댓글인 컬럼)가 해당 테이블의 다른 row(댓글인 row)의 PK값을 FK로 갖는데, 댓글에 해당하는 row는 객체가 생성되고 DB에 저장될 때 해당 컬럼에 null이 저장됩니다. 이는 Comment 객체의 ID에 @GenerateValue 설정을 주어서 그렇습니다. 위의 상황은 실무에서 사용할만큼 적절한가요? 아니라면 대안이 있을까요? jpa와 관련된 질문을 읽다보니, 다대일 관계에서 left join fetch의 경우 where문의 결과에 따라 데이터 일관성의 오류가 나타날 수 있다는 답변이 있었습니다.(해당 글: https://www.inflearn.com/questions/15876/fetch-join-%EC%8B%9C-%EB%B3%84%EC%B9%AD%EA%B4%80%EB%A0%A8-%EC%A7%88%EB%AC%B8%EC%9E%85%EB%8B%88%EB%8B%A4 ) 제가 작성한 테스트 코드의 쿼리문은 일대다 관계에서 일에 해당하는 엔티티에 별칭을 주어 where문을 적용한 것이므로 일관성의 문제가 발생하지 않는다고 생각했는데 이것이 옳은 생각인가요? 마지막으로 쿼리의 복잡도와 쿼리 개수는 trade off 관점에서, 특정 게시물에 관한 데이터를 반환해야 하는 api 요청이 들어왔을 때, 게시물과 댓글 엔티티가 단방향 관계일 경우 게시물에 관한 데이터와 댓글 및 대댓글에 관한 데이터를 각각의 저장소를 통해 가져오는 것이 좋을까요 혹은 쿼리가 다소 복잡해지더라도 한 번에 가져오는 것이 좋을까요? 아니면 단방향 관계를 양방향으로 만드는 것이 더 나은 선택일까요? 혼자 공부하니 올바른 방식을 찾는게 참으로 어려운 것 같습니다. 답변 기다리겠습니다. 감사합니다.

  • java
  • jpa
김민규 댓글 1 좋아요 0 조회수 389

003 강의 중 다른 문제 질문드립니다.

미해결

Flutter 초입문 왕초보편

flutter doctor 를 입력하라는 내용을 보고 따라 쳤는데 아래와 같은 문제가 발생하여 질문드립니다. flutter : 'flutter' 용어가 cmdlet, 함수, 스크립트 파일 또는 실행할 수 있는 프로그램 이름으로 인식되지 않습니다. 이름이 정확한지 확인하고 경로가 포함된 경우 경로가 올바른지 검증한 다음 다시 시도하십시오. 위치 줄:1 문자:1 + flutter doctor + ~~~~~~~ + CategoryInfo : ObjectNotFound: (flutter:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException

  • flutter
  • ios
  • android
  • dart
조태준 댓글 1 좋아요 0 조회수 975

section4 이미지 다운로드

해결됨

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

프로젝트 강의에 링크를 추가해 주셨다고 했는데 링크가 어디에 있는지 못 찾겠네요.. 깃허브 주소 치고 들어가도 github.com/serendipity1004/golden_rabbit_flutter_splash_screen 이 주소는 오류가 나요..ㅠㅠ

  • flutter
  • 클론코딩
이한별 댓글 1 좋아요 1 조회수 532

인기 태그

인프런 TOP Writers

주간 인기글