안녕하세요. 오늘은 ORM기능에 대해 소개 드리고자합니다.


ORM을 간단하게 설명드리자면 객체와 관계와의 설정이라 할 수 있습니다. 


DB의 병목 현상을 최소화하고 성능을 높이기 위해서 복잡한 기술들이 필요한데


아이펀 엔진에서 제공하는 ORM (Object Relational Mapping)을 이용하면


단순히 JSON형식으로 정의하는 것만으로도 DB의 데이터를 읽거나 쓸수 있게 도와줍니다.


아이펀엔진 이용하기에 먼저 준비해야될 환경 셋팅은 다음과 같습니다.


준비물 


1.  우분투 서버 14 LTS or 16 LTS , CentOS 6 Oor 7 

2.  Visual Studio 2015  or CLion , shell , MonoDevelop 

3.  (Visual Studio 2015인 경우) 아이펀엔진 개발자를 위한 비주얼 스튜디오 확장 프로그램입니다.
 https://marketplace.visualstudio.com/items?itemName=iFunEngineSupport.iFunEngineforVisualStudio-17995



* 참고로 저는 Hyper-V 에 아이펀 튜토리얼 에서 제공하는 이미지를 이용하여 우분투 16 lts 버전으로 셋팅하였습니다.

https://www.youtube.com/watch?v=EympbAzsLGE



비쥬얼 스튜디오 2015 버전 기준으로 설명드리겠습니다. 


준비물 3번 확장프로그램 설치까지 마친상태라고 가정하고 시작하겠습니다.


확장프로그램이 정상적으로 설치된 경우 새 프로젝트를 실행하면 템플릿 > Visual C++ 카테고리에 iFunEngine Project 가 보입니다.



저는 iFunEngineOrmTest 라는 이름으로 프로젝트를 생성할 예정입니다.




저같은 경우 이미 서버가 셋팅이 된 상태지만 처음 프로젝트를 실행하신분은 Remote Connection  > Create New Connection.. 

을 선택하면 아래 화면이 보입니다.



공란에 제가 기입한 내용대로 입력을 하시고 Connect 를 누른뒤 Create 메뉴를 선택하면 아래 화면과 같이 프로젝트에 필요한 리소스를 내려받습니다.



무사히 다운로드가 완료되었다면 아래와 같은 프로젝트 구조가 보여야 합니다.



처음 설치하면 example.json 이 보이고


Source 폴더에는 event_handlers.cc 와 i_fun_engine_orm_test_server.cc 등이 보입니다.


지금부터는 아이펀 팩토리의 메뉴얼 API 문서를 참조하시면서 수많은 기능들을 직접 개발 할 수 있습니다.


저는 초보자 관점에서 ORM을 이용해 디비를 생성하고 연결하고 데이터를 넣고 확인하는거 까지 소개 드리겠습니다.


example.json ORM을 정의하는 예제 json 규격의 파일입니다. 



{

  "User": {

    "Id": "String(16) KEY",

    "MyCharacter": "Character"

  },

  "Character": {

    "Name": "String(24) KEY",

    "Exp": "Integer",

    "Level": "Integer",

    "Hp": "Integer",

    "Mp": "Integer",

    "Sp": "Integer" 

  }

}



User는 문자열 키를 가지고 있고 ChracterName 문자열 키를 가지고 있습니다. 


그리고  MyCharacter 속성은 Chracter 라는 오브젝트 타입이 됩니다.


자세한 오브젝트 속성은 아래 메뉴얼을 통해 확인하시기 바랍니다.


ORM속성 : https://www.ifunfactory.com/engine/documents/reference/ko/object2.html#attribute


이상태에서 빌드 > 솔루션 빌드를 실행하게 되면 관련 클래스들이 자동으로 생성이 됩니다.




다음으로  MANIFEST.json 파일을 열어 "Object" 항목을 찾습니다. 


"Object": {

            "enable_database" : true,

            "cache_expiration_in_ms": 300000,

            "copy_cache_expiration_in_ms": 700,

            "enable_delayed_db_update" : false,

            "db_update_delay_in_second" : 10,

            "db_mysql_server_address" : "tcp://DB 주소를 입력해주세요. :3306",

            "db_mysql_id" : "MySql 계정 아이디를 입력해주세요",

            "db_mysql_pw" : "MySql 비번을 입력해주세요 ",

            "db_mysql_database" : "데이터베이스 이름을 입력해주세요",

            "db_read_connection_count" : 8,

            "db_write_connection_count" : 16,

            "db_key_shard_read_connection_count" : 8,

            "db_key_shard_write_connection_count" : 16,

            "db_character_set": "utf8",

            "use_db_select_transaction_isolation_level_read_uncommitted": true,

            "use_db_stored_procedure": true,

            "use_db_stored_procedure_full_name": true,

            "export_db_schema": false,

            "use_db_char_type_for_object_id": false,

            "enable_assert_no_rollback" : true,

            "object_id_pool_initial_count": 1000

          },


데이터베이스를 활성키 위해 enable_databaetrue로 변경하신 뒤


빨간색 표시를 한 부분을 가지고 계신 DB (MySql or MariaDB) 정보에 맞게 수정하시면됩니다. 


참고로 저는 AlibabaCloud의 후원을 받아 AlibabaCloud DB 서비스를 이용하였습니다.


다음으로  event_handler.cc 를 확인하면 


RegisterEventHandlers() 함수를 찾으시기 바랍니다. 



void RegisterEventHandlers() {

  /*

   * Registers handlers for session close/open events.

   */

  {

// 새로운 세션이 열리거나 닫힐때 불리는 핸들러 함수입니다. 새 세션이나 닫힌 세션이 인자로 전달됩니다.

    HandlerRegistry::Install2(OnSessionOpened, OnSessionClosed);

  }


   



  /*

   * Registers handlers for messages from the client.

   *

   * Handlers below are just for you reference.

   * Feel free to delete them and replace with your own.

   */

  {

    // 1. Registering a JSON message named "login" with its JSON schema.

    //    With json schema, Engine validates input messages in JSON.

    //    before entering a handler.

    //    You can specify a JSON schema like below, or you can also use

    //    auxiliary files in src/json_protocols directory.

    JsonSchema login_msg(JsonSchema::kObject,

        JsonSchema("facebook_uid", JsonSchema::kString, true),

        JsonSchema("facebook_access_token", JsonSchema::kString, true));

   

    HandlerRegistry::Register("login", OnAccountLogin, login_msg);


    // 2. Another JSON message example.

    //    In this time, we skipped a JSON schema.

    //    So no validation will be performed.

   HandlerRegistry::Register("echo", OnEchoMessage);

    


  // 사용자 정의 핸들러 입니다. 클라이언트로부터 id 값을 받으면 ORM 을 이용하여 데이터를 저장하는 과정을 설명하겠습니다.

   HandlerRegistry::Register("putId" , OnPutId);



    // 3. Registering a Google Protobuf message handler.

    //    Protobuf itself provides a validation using the "required" keyword.

    HandlerRegistry::Register2("pbuf_echo", OnPbufEchoMessage);





  }



int hp = 100;  // 유저 HP

int mp = 200; // 유저 MP


// 사용자 정의 함수입니다. 아이디 값을 받은뒤 처리하는 과정이 포함되어 있습니다.

void OnPutId(const Ptr<Session> &session, const Json &message) {

string id = message["id"].GetString();

Ptr<Character> c = Character::FetchByName(id);

if (not c) {

//  해당 캐릭터가 없는 경우 캐릭터를 생성합니다.

LOG(INFO) << "Not found. Created. " << id;

c = Character::Create(id);

}

else {

// 기존에 캐릭터가 있는 경우 HP와 MP 의 갱신된 데이터 값을 저장 합니다.

LOG(INFO) << "Found.";

c->SetHp(++hp);

c->SetMp(++mp);

}

}




 

다음 장에 설명드릴 유니티 클라이언트와 통신을 했을때 서버에서 ORM을 이용하여 데이터를 DB에 저장하는 과정을 보여드리기 위해 위와 같은 간단한 코드를 추가하였습니다. 


다시 빌드 후에  F5를 눌러 디버깅을 시작하시기 바랍니다.




디버그 이후에 출력창에 Starting 프로젝트 명이 정상적으로 출력되면 서버가 정상적으로 실행 된 것입니다.!!


다음장에는 유니티 클라이언트를 통해 TCP 방식으로 메시지를 전송하고 서버에서 ORM 을 처리하는 과정을 설명드리겠습니다. 


감사합니다. ^^