본문으로 건너뛰기

Database

1. 개요

Database는 실시간 데이터 처리와 동기화를 제공하는 시스템입니다. Reference 관계를 통해 연관된 데이터를 자동으로 처리하고 동기화합니다.

2. 핵심 기능

  • 실시간 데이터 동기화
  • Reference를 통한 자동 데이터 처리
  • 비동기 작업 처리
  • 분산 처리 지원

3. 데이터 모델 설계

// 캐릭터 모델
[Table("Characters")]
public class Character : BaseModel
{
[PrimaryKey("Id")]
public int Id { get; set; }

[Column("Name")]
public string Name { get; set; }

[Column("Level")]
public int Level { get; set; }

[Reference(typeof(Inventory))] // 인벤토리 참조 설정
public List<Inventory> Items { get; set; }
}

// 인벤토리 모델
[Table("Inventory")]
public class Inventory : BaseModel
{
[PrimaryKey("Id")]
public int Id { get; set; }

[Column("CharacterId")]
public int CharacterId { get; set; }

[Column("ItemId")]
public int ItemId { get; set; }

[Column("Slot")]
public int Slot { get; set; }

[Column("Amount")]
public int Amount { get; set; }
}

4. 기본 사용법

클라이언트 초기화

public class GameManager : MonoBehaviour
{
private BACKND.Database.Client _client;

void Start()
{
_client = new BACKND.Database.Client();
}
}

데이터 생성

private IEnumerator CreateCharacter(string name)
{
var character = new Character
{
Name = name,
Level = 1,
Items = new List<Inventory>() // 빈 인벤토리로 시작
};

yield return _client.From<Character>().Insert(character);
}

데이터 조회

private IEnumerator GetCharacter(int characterId)
{
var op = _client.From<Character>()
.Include(x => x.Items) // 인벤토리도 함께 로드
.Where(x => x.Id == characterId)
.First();
yield return op;

var character = op.Current as Character;
if (character != null)
{
Debug.Log($"캐릭터: {character.Name}, 아이템 수: {character.Items.Count}");
}
}

5. 인벤토리 시스템 예제

인벤토리 관리자

public class InventoryManager : MonoBehaviour
{
private BACKND.Database.Client _client;

// 아이템 추가
private IEnumerator AddItem(int characterId, int itemId, int amount, int slot)
{
var op = _client.From<Character>()
.Include(x => x.Items)
.Where(x => x.Id == characterId)
.First();
yield return op;

var character = op.Current as Character;
if (character != null)
{
// 새 아이템을 캐릭터의 인벤토리에 추가
character.Items.Add(new Inventory
{
CharacterId = characterId,
ItemId = itemId,
Amount = amount,
Slot = slot
});

// 캐릭터 업데이트 시 인벤토리도 자동으로 처리됨
yield return _client.From<Character>()
.Where(x => x.Id == characterId)
.Update(character);
}
}

// 아이템 이동
private IEnumerator MoveItem(int characterId, int fromSlot, int toSlot)
{
var op = _client.From<Character>()
.Include(x => x.Items)
.Where(x => x.Id == characterId)
.First();
yield return op;

var character = op.Current as Character;
if (character != null)
{
var items = character.Items;
var fromItem = items.FirstOrDefault(x => x.Slot == fromSlot);
var toItem = items.FirstOrDefault(x => x.Slot == toSlot);

if (fromItem != null)
{
fromItem.Slot = toSlot;
if (toItem != null)
{
toItem.Slot = fromSlot;
}

// 캐릭터 업데이트하면 변경된 슬롯 정보도 자동 저장
yield return _client.From<Character>()
.Where(x => x.Id == characterId)
.Update(character);
}
}
}

// 아이템 제거
private IEnumerator RemoveItem(int characterId, int slot)
{
var op = _client.From<Character>()
.Include(x => x.Items)
.Where(x => x.Id == characterId)
.First();
yield return op;

var character = op.Current as Character;
if (character != null)
{
// 해당 슬롯의 아이템 제거
character.Items.RemoveAll(x => x.Slot == slot);

// 캐릭터 업데이트하면 아이템 삭제도 자동 처리
yield return _client.From<Character>()
.Where(x => x.Id == characterId)
.Update(character);
}
}
}

6. 주의사항 및 팁

작업 순서

// 좋은 예: 메모리의 데이터를 수정하고 한 번에 업데이트
character.Items.Add(newItem);
yield return _client.From<Character>().Update(character);

// 나쁜 예: 불필요한 DB 작업
yield return _client.From<Inventory>().Insert(newItem); // 불필요
yield return _client.From<Character>().Update(character);

Include 활용

// 좋은 예: Include로 한 번에 로드
var op = _client.From<Character>()
.Include(x => x.Items)
.First();

// 나쁜 예: 여러 번 쿼리
var charOp = _client.From<Character>().First();
var itemsOp = _client.From<Inventory>().Where(...);

null 체크

// 항상 null 체크 수행
if (character?.Items != null)
{
// 안전하게 처리
}
핵심 포인트
  1. Reference 관계가 있으면 부모 객체 업데이트 시 자식 객체도 자동으로 처리됩니다
  2. 데이터 수정은 메모리에서 하고 한 번의 Update로 저장하세요
  3. Include를 적극 활용해 쿼리 횟수를 줄이세요
  4. 모든 DB 작업은 반드시 yield return으로 처리하세요