Flutter에서 GraphQL로 소프트웨어 데이터 관계 저장
GraphQL을 사용하여 관계형 데이터 저장하기
소개
지난 두 개의 튜토리얼에서는 Flutter 앱 프로젝트에서 Back4App 데이터베이스에 대해 GraphQL 쿼리와 변형을 수행했습니다. 우리는 GraphQL Flutter를 GraphQL 클라이언트로 사용하고 있습니다. 이는 매우 강력하고 널리 사용되는 프로젝트입니다. 이러한 튜토리얼에서는 클래스에 가장 일반적인 유형을 가진 매우 간단한 데이터 모델을 사용했습니다.
Back4App은 관계형 데이터를 생성, 저장 및 쿼리할 수 있는 유연한 플랫폼입니다. 이 튜토리얼에서는 Back4App 백엔드에서 관계형 데이터를 저장하고 쿼리할 때 관계 및 포인터를 사용하는 방법을 보여주면서 이 기능을 깊이 탐구할 것입니다. 또한 Back4App이 제공하는 다른 데이터 유형인 GeoPointer 및 Datetime도 탐색할 것입니다.
목표
이 기사 끝에서 여러분은 다음을 할 수 있게 될 것입니다:
- 관계형 데이터 생성/업데이트 및 삭제 (포인터 및 관계 사용)
- GeoPointers 생성/업데이트
- 날짜-시간 생성/업데이트.
전제 조건
이 튜토리얼을 완료하려면 다음이 필요합니다:
- VS Code 또는 Android Studio와 같은 Flutter IDE에서 다운로드한 프로젝트를 엽니다.
1 - 백엔드 설정
우리의 이전 프로젝트에서 우리의 데이터 모델은 단일 클래스인 Language로 매우 간단했습니다. 이제 우리는 Language와 관련된 2개의 새로운 클래스를 추가하여 더 복잡하게 만들 것입니다.
형식이 있는 창립자
열 이름 | 설명 |
|---|---|
이름 | 언어의 창립자 이름 |
열 이름 | 설명 |
|---|---|
이름 | 소유 회사 이름 |
소유 날짜 | 회사가 소유권을 얻은 날짜 |
본사 | 회사의 본사 위치 |
우리는 클래스 Language와 클래스 Founder 간의 일대일 관계를 Parse Pointers를 사용하여 생성할 것입니다. 이는 특정 언어의 창립자를 알려줍니다. 그런 다음, 우리는 클래스 Language와 클래스 Ownership 간의 일대다 관계를 Parse Relations를 사용하여 생성할 것입니다. 이는 어떤 조직/회사가 언어를 소유하고 있는지, 그들의 본사 및 언어 소유권을 취득한 날짜를 알려줍니다. 데이터 모델은 다음과 같이 보일 것입니다:

우리 앱으로 이동하기 전에 필요한 클래스와 데이터를 백엔드에 생성합시다. Back4App 앱으로 가서 GraphQL Playground로 이동합니다. 아래의 뮤테이션을 사용하여 클래스 Founder를 생성하여 언어의 창립자 이름을 저장할 것입니다.
1 mutation CreateClass {
2 createClass(input:{
3 name: "Founder"
4 schemaFields: {
5 addStrings: [{name: "name"}]
6 }
7 }){
8 class{
9 schemaFields{
10 name
11 __typename
12 }
13 }
14 }
15 }이제 창립자의 이름으로 클래스를 채워봅시다. 다음 단계에서는 이 데이터를 사용하여 창립자 클래스에 포인팅하는 새로운 언어를 생성할 것입니다. 아래의 변이를 Back4App GraphQL Playground에서 사용하여 창립자를 생성하세요.
1 mutation CreateObject{
2 createFounder(input: {fields: {name: "James Gosling"}}){
3 founder{
4 id
5 name
6 }
7 }
8 }여기에서 우리는 JAVA 프로그래밍 언어 창립자의 이름을 입력했습니다. 다른 사람들에 대해서도 비슷하게 할 수 있지만 지금은 이것으로 가이드를 충분히 진행할 수 있습니다.
이제 Ownership 클래스를 생성하여 언어 소유권, 설립 날짜(날짜-시간) 및 소유자의 본사 위치(GeoPointer)를 저장할 것입니다. 나중에 언어 클래스와 소유권 간의 관계를 생성할 것입니다. 아래 코드를 실행하여 클래스를 생성하세요:
1 mutation CreateClass {
2 createClass(input:{
3 name: "Ownership"
4 schemaFields: {
5 addStrings: [{name: "name"}]
6 addDates: [{name: "date_owned"}]
7 }
8 }){
9 class{
10 schemaFields{
11 name
12 __typename
13 }
14 }
15 }
16 } 이제 다음 변형을 사용하여 Ownership 클래스를 채우십시오:
1 mutation CreateObject{
2 createOwnership(input: {fields: {name: "Sun Microsystems"}}){
3 ownership{
4 id
5 name
6 }
7 }
8 }1 mutation CreateObject{
2 createOwnership(input: {fields: {name: "Oracle"}}){
3 ownership{
4 id
5 name
6 }
7 }
8 }이제 페이지를 새로 고치고, Ownership 클래스로 데이터베이스 브라우저로 이동하십시오. 오른쪽 상단에서 새 열 추가를 선택하십시오. 첫 번째 드롭다운에서 GeoPoint를 선택하고 두 번째 텍스트 필드에 headquarters라고 이름을 지정하십시오. 그리고 모든 것을 그대로 두고 열 추가 버튼을 누르십시오.

그런 다음 데이터베이스 브라우저에서 언어 수업으로 가십시오. 관계를 추가해 보겠습니다 소유권 및 창립자 클래스에. 새 열 추가를 클릭한 다음 데이터 유형 포인터와 대상 클래스 선택: 창립자. 열에 동일한 이름 - 창립자 - 을 부여한 후 열 추가를 누르십시오.

이제 소유권이라는 새 열을 추가하여 관계 데이터 유형을 사용하고 클래스 소유권을 선택하여 이 과정을 반복하십시오.

이제 Flutter 앱에서 사용할 데이터 모델이 준비되었으며 데이터를 저장하고 업데이트할 수 있습니다.
2 - 포인터 생성/추가 및 삭제
이제 프로젝트 보일러플레이트 코드를 GitHub 리포지토리에서 다운로드하여 IDE에서 엽니다. Back4App에 프로젝트를 연결하려면 GraphQL Playground로 이동하여 아래 이미지에 표시된 대로 키와 API URL을 복사합니다. 이제 이를 constants.dart에 붙여넣고 프로젝트를 실행합니다.

에뮬레이터에서 애플리케이션을 실행합니다. 하단의 M 플로팅 버튼으로 이동합니다. 그러면 간단한 변형을 수행했던 페이지로 이동합니다. 여기에서 추가 플로팅 액션 버튼 CM, 복잡한 GraphQL 변형을 수행하는 데 사용할 버튼입니다. CM 버튼을 클릭하면 이 가이드에서 수행할 각 작업에 대한 네 개의 버튼이 표시됩니다.
이제 databaseutils.dart 파일을 열고 addPointers() 메서드로 스크롤합니다. 여기에서 포인터 추가 로직을 추가할 것입니다. 우리는 James Gosling을 Java 언어의 창립자로 지정할 것입니다. 따라서 먼저 Back4App 백엔드로 이동하여 창립자(James Gosling)와 언어(Java)의 objectId를 복사해야 합니다.
데이터에 대한 포인터 업데이트/생성
우리 앱으로 진행하십시오 databaseutils.dart 및 addPointers() 메서드에서 String addPointerQuery를 초기화하여 Pointers를 추가하기 위한 GraphQL 쿼리를 다음과 같이 할당합니다:
1 String addPointerQuery=
2 '''
3 mutation addPointer(\$languageId: ID!, \$founderId: UpdateLanguageFieldsInput! ){
4 updateLanguage(input : {id : \$languageId, fields : \$founderId})
5 {
6 language{
7 objectId
8 }
9 }
10 }
11 ''';그리고 final 변수를 초기화하여 변수를 할당합니다. rowObjectId와 pointersId를 매개변수로 사용합니다.
- rowObjectId- 우리가 가리킬 행의 객체 ID
- pointersId- 가리킬 행의 객체 ID.
따라서 변수를 다음과 같이 선언합니다:
1 final variable={
2 "userId" : rowObjectId,
3 "founderId": {
4 "founder": {
5 "link": pointersId
6 }
7 }
8 };이제 마지막 가이드처럼 GraphQLClient를 초기화하고 QueryOptions()의 도움으로 쿼리를 전송하고 QueryResults()의 인스턴스를 반환합니다.
1 GraphQlConfiguration configuration = GraphQlConfiguration();
2 GraphQLClient client = configuration.clientToQuery();
3
4 QueryResult queryResult = await client.query(
5 QueryOptions(documentNode: gql(addPointerQuery), variables: variable),
6 );
7 return queryResult;당신의 addPointers() 메서드는 다음과 같아야 합니다:
1 Future<QueryResult> addPointers(String rowObjectId, String pointersId) async{
2 print('addPointers');
3 //code for add/update Pointers
4 String addPointerQuery=
5 '''
6 mutation addPointer(\$languageId: ID!, \$founderId: UpdateLanguageFieldsInput! ){
7 updateLanguage(input : {id : \$languageId, fields : \$founderId})
8 {
9 language{
10 objectId
11 }
12 }
13 }
14 ''';
15 final variable={
16 "userId" : rowObjectId,
17 "founderId": {
18 "founder": {
19 "link": pointersId
20 }
21 }
22 };
23 GraphQlConfiguration configuration = GraphQlConfiguration();
24 GraphQLClient client = configuration.clientToQuery();
25
26 QueryResult queryResult = await client.query(
27 QueryOptions(documentNode: gql(addPointerQuery), variables: variable),
28 );
29 return queryResult;
30 }이제 앱을 핫 리스타트하고, CM 버튼을 클릭한 후 Add Pointers 버튼을 누르세요. 여기서 첫 번째 텍스트 필드에 포인터를 추가해야 하는 objectId를 입력하고, 두 번째 텍스트 필드에 포인터가 가리킬 objectId를 입력한 후 Done. 이제 대시보드를 확인하면 founder 열 아래에 관계를 볼 수 있어야 합니다. 클릭하면 Founder 클래스가 가리키는 행으로 이동합니다.
데이터에 대한 포인터 삭제
이제 관계를 삭제하는 로직을 작성할 deletePointers() 메서드로 진행합니다. 관계를 삭제하려면 위의 쿼리에 약간의 변경만 하면 됩니다. 즉, 변수에서 "link"를 "remove"로 변경하면 됩니다. 따라서 final variable을 초기화한 후에는 다음과 같을 것입니다:
1 final variable={
2 "languageId" : rowObjectId,
3 "founderId": {
4 "founder": {
5 "remove": pointersId
6 }
7 }
8 };나머지는 addPointers()와 정확히 동일하게 보일 것입니다. 따라서 당신의 deletePointers() 메서드는 다음과 같습니다:
1 Future<QueryResult> deletePointers(String rowObjectId, String pointersId) async{
2 print('deletePointers');
3 //code for delete pointers
4 String removePointersQuery=
5 '''
6 mutation addPointer(\$languageId: ID!, \$founderId: UpdateLanguageFieldsInput! ){
7 updateLanguage(input : {id : \$languageId, fields : \$founderId})
8 {
9 language{
10 objectId
11 }
12 }
13 }
14 ''';
15 final variable={
16 "languageId" : rowObjectId,
17 "founderId": {
18 "founder": {
19 "remove": pointersId
20 }
21 }
22 };
23 GraphQlConfiguration configuration = GraphQlConfiguration();
24 GraphQLClient client = configuration.clientToQuery();
25
26 QueryResult queryResult = await client.query(
27 QueryOptions(documentNode: gql(removePointersQuery), variables: variable),
28 );
29 return queryResult;
30
31 }이제 Back4App 대시보드로 이동하여 특정 행의 *창립자 열이 삭제된 것을 확인할 수 있습니다.
3 - 날짜-시간 데이터 생성/추가 및 삭제
기억하신다면 우리는 Ownership 클래스를 Step 1에서 생성하고 그 안에 데이터를 저장했습니다. 이들은 Java 프로그래밍 언어를 소유한 회사들의 이름입니다. 그러므로 먼저 소유권을 취득한 날짜를 입력해 보겠습니다.
이제 databaseutils.dart로 이동하여 addDateTime() 함수를 생성하거나 스크롤하여 찾습니다. 여기서 우리는 클래스에 날짜-시간 데이터 유형을 추가하는 로직을 작성할 것입니다. String addDateTimeQuery를 초기화하고 날짜-시간 데이터를 생성하기 위한 쿼리를 할당합니다:
1 String addDateTimeQuery=
2 '''
3 mutation addTime(\$rowId: ID!,\$dateOwned: Date!){
4 updateOwnership(input : {id : \$rowId, fields : {date_owned : \$dateOwned}})
5 {
6 ownership{
7 objectId
8 }
9 }
10 }
11 ''';그리고 final 변수는 다음과 같습니다:
1 final variable={
2 "rowId": rowObjectId,
3 "dateOwned": dateTime
4 };이제 GraphQLClient를 초기화하고 QueryOption()을 통해 쿼리를 전달하세요. 이것이 당신의 함수가 어떻게 보일지입니다:
1 Future<QueryResult> addDateTime(String rowObjectId, String dateTime) async{
2 print('addDateTime');
3 //code for add/update date-time
4 String addDateTimeQuery=
5 '''
6 mutation addTime(\$rowId: ID!,\$dateOwned: Date!){
7 updateOwnership(input : {id : \$rowId, fields : {date_owned : \$dateOwned}})
8 {
9 ownership{
10 objectId
11 }
12 }
13 }
14 ''';
15 final variable={
16 "rowId": rowObjectId,
17 "dateOwned": dateTime
18 };
19 GraphQlConfiguration configuration = GraphQlConfiguration();
20 GraphQLClient client = configuration.clientToQuery();
21 QueryResult queryResult = await client.query(
22 QueryOptions(documentNode: gql(addDateTimeQuery), variables: variable),
23 );
24 return queryResult;
25 }이제 Hot Restart 애플리케이션을 실행하고 objectId를 기록하세요. Sun Microsystems이 포함된 행의 name 열에서. Add Date-time 버튼을 누르세요. 이제 첫 번째 텍스트 필드에 기록한 objectId를 입력하고 “02-24-1982”를 MM-DD-YYYY 형식으로 입력한 후 Java가 발표된 날에 Done 버튼을 누르세요.
Back4App 백엔드로 진행하면 24 Feb 1982 at 00:00:00 UTC 형식으로 날짜가 표시되며, 이는 데이터 유형이 날짜-시간 데이터 유형으로 식별되었음을 의미합니다. 마찬가지로 “01-27-2010”을 date_owned에 추가할 수 있습니다.Oracle에 대해.
4 - GeoPointer 데이터 추가/업데이트
회사의 본사를 찾기 위해 Ownership 테이블에 GeoPointer 데이터를 추가해 보겠습니다. database_utils.dart 파일로 이동하여 아래로 스크롤하여 addGeoPointers() 함수로 가십시오. 이제 String addGeoPointers를 초기화하고 해당 쿼리를 할당합니다:
1 String addGeoPointers=
2 '''
3 mutation addGeoPointer(\$objectId: ID!,\$latitude: Float!,\$longitude: Float!){
4 updateOwnership(input : {id : \$objectId, fields : { headquarters: {latitude : \$latitude, longitude : \$longitude}}})
5 {
6 ownership{
7 objectId
8 }
9 }
10 }
11 ''';그리고 final variable로:
1 final variable={
2 "objectId": rowObjectId,
3 "latitude": double.parse(latitude),
4 "longitude": double.parse(longitude),
5 };위도 latitude와 longitude가 double 값이므로, 이를 String에서 double로 파싱해야 합니다. GrapQLClient를 초기화하고 QueryOption()로 쿼리를 전달합니다. 이렇게 하면 addGeoPointers() 함수는 다음과 같이 보일 것입니다:
1 Future<QueryResult> addGeoPointers(String rowObjectId, String latitude, String longitude) async{
2 print('add GeoPointers');
3 //code for add/update Geopointers
4 String addGeoPointers=
5 '''
6 mutation addGeoPointer(\$objectId: ID!,\$latitude: Float!,\$longitude: Float!){
7 updateOwnership(input : {id : \$objectId, fields : { headquarters: {latitude : \$latitude, longitude : \$longitude}}})
8 {
9 ownership{
10 objectId
11 }
12 }
13 }
14 ''';
15 final variable={
16 "objectId": rowObjectId,
17 "latitude": double.parse(latitude),
18 "longitude": double.parse(longitude),
19 };
20 GraphQlConfiguration configuration = GraphQlConfiguration();
21 GraphQLClient client = configuration.clientToQuery();
22 QueryResult queryResult = await client.query(
23 QueryOptions(documentNode: gql(addGeoPointers), variables: variable),
24 );
25 return queryResult;
26 }앱을 핫 리스타트하고 Add GeoPointers 버튼을 선택하세요. 첫 번째 텍스트 상자에 37.35를 입력하고 두 번째 텍스트 상자에 121.95를 입력하세요. Sun Microsystems의 objectId를 입력하고 name을 입력한 후 완료를 누르세요. 이제 Back4App 백엔드로 이동하면 (37.35, 121.95)가 표시되며, 이는 본사를 나타내는 좌표로 GeoPointers로 식별됩니다.

5 - 관계 추가/업데이트 및 삭제
포인터는 한 행만 가리킬 수 있지만, 관계의 도움으로 여러 행에 연결할 수 있습니다. 따라서 Language 테이블을 Ownership의 Java 언어에 대해 이 두 행과 관계를 맺어 보겠습니다.
관계 추가/업데이트
다음으로 진행하십시오 database_utils.dart 파일로 가서 addRelation() 함수로 로직을 작성하십시오. String addRelationQuery를 초기화하고 관계에 대한 쿼리를 다음과 같이 할당하십시오:
1 String addRelationQuery=
2 '''
3 mutation addRelation(\$objectId: ID!, \$relationId: OwnershipRelationInput){
4 updateLanguage(input : {id : \$objectId, fields : {ownership : \$relationId}})
5 {
6 language{
7 objectId
8 }
9 }
10 }
11 ''';그리고 최종 변수는 다음과 같습니다:
1 final variable= {
2 "objectId": objectId,
3 "relationId": relationId
4 };따라서 GraphQLClient를 초기화하고 이전과 같이 쿼리를 전달한 후, 당신의 database_utils.dart는 다음과 같이 보일 것입니다:
1 Future<QueryResult> addRelation(String rowObjectId, String relationId) async{
2 //code for add/update Relation.
3 print('addRelation');
4 String addRelationQuery=
5 '''
6 mutation addRelation(\$objectId: ID!, \$relationId: OwnershipRelationInput){
7 updateLanguage(input : {id : \$objectId, fields : {ownership : \$relationId}})
8 {
9 language{
10 objectId
11 }
12 }
13 }
14 ''';
15 final variable= {
16 "objectId": rowObjectId,
17 "relationId": {
18 "add": relationId
19 }
20 };
21 GraphQlConfiguration configuration = GraphQlConfiguration();
22 GraphQLClient client = configuration.clientToQuery();
23 QueryResult queryResult = await client.query(
24 QueryOptions(documentNode: gql(addRelationQuery), variables: variable),
25 );
26 print(queryResult);
27 return queryResult;
28 }성공 귀하의 앱이 드디어 Back4App에 관계형, 날짜 및 GeoPointers 데이터를 저장했습니다!
결론
이 가이드에서는 Flutter 앱 프로젝트를 사용하여 Back4App에 관계형 데이터를 저장하는 방법을 배웠습니다. 또한 GeoPointers 및 Datetime과 같은 다른 GraphQL 변형을 사용하여 데이터를 생성, 업데이트 및 삭제하는 작업을 수행했습니다. 다음 튜토리얼에서는 Flutter 앱에 대한 쿼리를 깊이 있게 다룰 것입니다.
이 가이드는 HybrowLabs에 의해 작성되었습니다.