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)
{
// 안전하게 처리
}
핵심 포인트
- Reference 관계가 있으면 부모 객체 업데이트 시 자식 객체도 자동으로 처리됩니다
- 데이터 수정은 메모리에서 하고 한 번의 Update로 저장하세요
- Include를 적극 활용해 쿼리 횟수를 줄이세요
- 모든 DB 작업은 반드시 yield return으로 처리하세요