Skip to main content

Database

1. Overview

The database is a system that provides real-time data processing and synchronization. It automatically processes and synchronizes related data through reference relationships.

2. Key Features

  • Real-time data synchronization
  • Automatic data processing through references
  • Asynchronous task handling
  • Distributed processing support

3. Data Model Design

// Character model
[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))] // Inventory reference settings
public List<Inventory> Items { get; set; }
}

// Inventory model
[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. Basic Use

Client Initialization

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

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

Creating Data

private IEnumerator CreateCharacter(string name)
{
var character = new Character
{
Name = name,
Level = 1,
Items = new List<Inventory>() // Start with an empty inventory
};

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

Lookup Data

private IEnumerator GetCharacter(int characterId)
{
var op = _client.From<Character>()
.Include(x => x.Items) // Load inventory as well
.Where(x => x.Id == characterId)
.First();
yield return op;

var character = op.Current as Character;
if (character != null)
{
Debug.Log($"Character: {character.Name}, Number of items: {character.Items.Count}");
}
}

5. Inventory System Example

Inventory Manager

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

// Add item
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)
{
// Add new items in character's inventory
character.Items.Add(new Inventory
{
CharacterId = characterId,
ItemId = itemId,
Amount = amount,
Slot = slot
});

// Inventory is automatically processed upon updating character
yield return _client.From<Character>()
.Where(x => x.Id == characterId)
.Update(character);
}
}

// Move item
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;
}

// Modified slot info is also automatically saved upon updating character
yield return _client.From<Character>()
.Where(x => x.Id == characterId)
.Update(character);
}
}
}

// Remove item
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)
{
// Remove item in the slot
character.Items.RemoveAll(x => x.Slot == slot);

// Item deletion automaticalled processed upon character update
yield return _client.From<Character>()
.Where(x => x.Id == characterId)
.Update(character);
}
}
}

6. Precautions and Tips

Workflow

// Good Example: Modify data in memory and update all at once
character.Items.Add(newItem);
yield return _client.From<Character>().Update(character);

// Bad Example: Unnecessary DB operations
yield return _client.From<Inventory>().Insert(newItem); // Unnecessary
yield return _client.From<Character>().Update(character);

Using Include

// Good Example: Load everything at once using Include
var op = _client.From<Character>()
.Include(x => x.Items)
.First();

// Bad Example: Multiple queries
var charOp = _client.From<Character>().First();
var itemsOp = _client.From<Inventory>().Where(...);

null Checks

// Always perform a null check
if (character?.Items != null)
{
// Process safely
}
Key Points
  1. If there is a reference relationship, when the parent object is updated, the child objects are also automatically handled.
  2. Modify data in memory and save it with a single update.
  3. Actively use Include to reduce the number of queries.
  4. Always handle DB operations with yield return. :::