ObjectRepository - ํ™ˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์œ„ํ•œ .NET ์ธ๋ฉ”๋ชจ๋ฆฌ ์ €์žฅ์†Œ ํŒจํ„ด

์™œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•ฉ๋‹ˆ๊นŒ?

์›น์‚ฌ์ดํŠธ๋‚˜ ๋ฐฑ์—”๋“œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๋ถ€๋ถ„์˜ ์ œ์ •์‹ ์ธ ์‚ฌ๋žŒ๋“ค์ด ๊ฐ€์žฅ ๋จผ์ € ์›ํ•˜๋Š” ๊ฒƒ์€ SQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. 

๊ทธ๋Ÿฌ๋‚˜ ๋•Œ๋กœ๋Š” ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์ด SQL์— ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค๋Š” ์ƒ๊ฐ์ด ๋– ์˜ค๋ฆ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๊ฒ€์ƒ‰ ๋˜๋Š” ์†Œ์…œ ๊ทธ๋ž˜ํ”„๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๊ฐœ์ฒด ๊ฐ„์˜ ๋ณต์žกํ•œ ๊ด€๊ณ„๋ฅผ ๊ฒ€์ƒ‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

์ตœ์•…์˜ ์ƒํ™ฉ์€ ํŒ€์œผ๋กœ ์ž‘์—…ํ•˜๊ณ  ๋™๋ฃŒ๊ฐ€ ๋น ๋ฅธ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ๋ฉ”์ธ ํŽ˜์ด์ง€์˜ SELECT๊ฐ€ ํ•ฉ๋ฆฌ์ ์ธ ์‹œ๊ฐ„ ๋‚ด์— ์™„๋ฃŒ๋˜๋„๋ก N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์ถ”๊ฐ€ ์ธ๋ฑ์Šค๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ์‹œ๊ฐ„์„ ์†Œ๋น„ํ•˜์…จ๋‚˜์š”?

๋˜ ๋‹ค๋ฅธ ์ธ๊ธฐ ์žˆ๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์€ NoSQL์ž…๋‹ˆ๋‹ค. ๋ช‡ ๋…„ ์ „์—๋Š” ์ด ์ฃผ์ œ์— ๋Œ€ํ•ด ๋งŽ์€ ๊ณผ์žฅ๋œ ์ด์•ผ๊ธฐ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํŽธ๋ฆฌํ•œ ๊ฒฝ์šฐ๋ฅผ ์œ„ํ•ด MongoDB๋ฅผ ๋ฐฐํฌํ–ˆ๊ณ  json ๋ฌธ์„œ ํ˜•์‹์˜ ๋‹ต๋ณ€์— ๋งŒ์กฑํ–ˆ์Šต๋‹ˆ๋‹ค. (๊ทธ๋Ÿฐ๋ฐ ๋ฌธ์„œ์— ์ˆœํ™˜๋งํฌ๊ฐ€ ์žˆ์–ด์„œ ๋ชฉ๋ฐœ์„ ๋ช‡ ๊ฐœ๋‚˜ ๊ฝ‚์•„์•ผ ํ–ˆ๋‚˜?).

๋‹ค๋ฅธ ๋Œ€์ฒด ๋ฐฉ๋ฒ•์„ ์‹œ๋„ํ•ด ๋ณผ ๊ฒƒ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•˜๊ณ  ์ฃผ๊ธฐ์ ์œผ๋กœ ์ž„์˜ ์ €์žฅ์†Œ(ํŒŒ์ผ, ์›๊ฒฉ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค)์— ์ €์žฅํ•ด ๋ณด๋Š” ๊ฒƒ์€ ์–ด๋–จ๊นŒ์š”? 

๋ฉ”๋ชจ๋ฆฌ๋Š” ์ €๋ ดํ•ด์กŒ์œผ๋ฉฐ ๋Œ€๋ถ€๋ถ„์˜ ์ค‘์†Œ ๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋Š” 1GB ๋ฉ”๋ชจ๋ฆฌ์— ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค. (์˜ˆ๋ฅผ ๋“ค์–ด, ์ œ๊ฐ€ ๊ฐ€์žฅ ์ข‹์•„ํ•˜๋Š” ํ™ˆ ํ”„๋กœ์ ํŠธ๋Š” ๊ธˆ์œต ์ถ”์ ๊ธฐ45๋…„ ๋ฐ˜ ๋™์•ˆ ๋‚˜์˜ ์ง€์ถœ, ์ž”์•ก, ๊ฑฐ๋ž˜์— ๋Œ€ํ•œ ์ผ์ผ ํ†ต๊ณ„์™€ ๋‚ด์—ญ์„ ๋ณด๊ด€ํ•˜๋Š” ๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ XNUMXMB๋งŒ ์†Œ๋ชจํ•ฉ๋‹ˆ๋‹ค.

์žฅ์  :

  • ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๊ฐ€ ๋” ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค. ์ฟผ๋ฆฌ, ์ง€์—ฐ ๋กœ๋”ฉ, ORM ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ์ผ๋ฐ˜ C# ๊ฐœ์ฒด๋กœ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ์˜ ์•ก์„ธ์Šค์™€ ๊ด€๋ จ๋œ ๋ฌธ์ œ๋Š” ์—†์Šต๋‹ˆ๋‹ค.
  • ๋งค์šฐ ๋น ๋ฆ…๋‹ˆ๋‹ค - ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์—†๊ณ , ์ฝ”๋“œ๋ฅผ ์ฟผ๋ฆฌ ์–ธ์–ด๋กœ ๋ณ€ํ™˜ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๊ฐ์ฒด๋ฅผ (์—ญ)์ง๋ ฌํ™”ํ•  ํ•„์š”๋„ ์—†์Šต๋‹ˆ๋‹ค.
  • ๋””์Šคํฌ์˜ XML, SQL Server, Azure Table Storage ๋“ฑ ์–ด๋–ค ํ˜•์‹์œผ๋กœ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ์  :

  • ์ˆ˜ํ‰์  ํ™•์žฅ์ด ์†์‹ค๋˜๊ณ  ๊ฒฐ๊ณผ์ ์œผ๋กœ ๊ฐ€๋™ ์ค‘์ง€ ์‹œ๊ฐ„์ด ์—†๋Š” ๋ฐฐํฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด ์ถฉ๋Œํ•˜๋ฉด ๋ถ€๋ถ„์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์†์‹ค๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๊ฒฐ์ฝ” ์ถฉ๋Œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ฃ ?)

์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?

์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์ฒ˜์Œ์—๋Š” ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ์™€ ์—ฐ๊ฒฐ์ด ์„ค์ •๋˜๊ณ  ๋ฐ์ดํ„ฐ๊ฐ€ ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค.
  • ๊ฐœ์ฒด ๋ชจ๋ธ, ๊ธฐ๋ณธ ์ธ๋ฑ์Šค ๋ฐ ๊ด€๊ณ„ํ˜• ์ธ๋ฑ์Šค(1:1, 1:๋‹ค)๊ฐ€ ๊ตฌ์ถ•๋ฉ๋‹ˆ๋‹ค.
  • ๊ฐœ์ฒด ์†์„ฑ ๋ณ€๊ฒฝ(INotifyPropertyChanged) ๋ฐ ์ปฌ๋ ‰์…˜์— ์š”์†Œ ์ถ”๊ฐ€ ๋˜๋Š” ์ œ๊ฑฐ(INotifyCollectionChanged)์— ๋Œ€ํ•œ ๊ตฌ๋…์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  • ๊ตฌ๋…์ด ํŠธ๋ฆฌ๊ฑฐ๋˜๋ฉด ๋ณ€๊ฒฝ๋œ ๊ฐ์ฒด๊ฐ€ ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ์— ์“ฐ๊ธฐ ์œ„ํ•ด ํ์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.
  • ์ €์žฅ์†Œ์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ์— ์ฃผ๊ธฐ์ ์œผ๋กœ(ํƒ€์ด๋จธ์— ๋”ฐ๋ผ) ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ข…๋ฃŒํ•˜๋ฉด ๋ณ€๊ฒฝ ์‚ฌํ•ญ๋„ ์ €์žฅ์†Œ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ ์˜ˆ

ํ•„์š”ํ•œ ์ข…์†์„ฑ ์ถ”๊ฐ€

// ะžัะฝะพะฒะฝะฐั ะฑะธะฑะปะธะพั‚ะตะบะฐ
Install-Package OutCode.EscapeTeams.ObjectRepository
    
// ะฅั€ะฐะฝะธะปะธั‰ะต ะดะฐะฝะฝั‹ั…, ะฒ ะบะพั‚ะพั€ะพะผ ะฑัƒะดัƒั‚ ัะพั…ั€ะฐะฝัั‚ัŒัั ะธะทะผะตะฝะตะฝะธั
// ะ˜ัะฟะพะปัŒะทัƒะนั‚ะต ั‚ะพ, ะบะพั‚ะพั€ั‹ะผ ะฑัƒะดะตั‚ะต ะฟะพะปัŒะทะพะฒะฐั‚ัŒัั.
Install-Package OutCode.EscapeTeams.ObjectRepository.File
Install-Package OutCode.EscapeTeams.ObjectRepository.LiteDb
Install-Package OutCode.EscapeTeams.ObjectRepository.AzureTableStorage
    
// ะžะฟั†ะธะพะฝะฐะปัŒะฝะพ - ะตัะปะธ ะฝัƒะถะฝะพ ั…ั€ะฐะฝะธั‚ัŒ ะผะพะดะตะปัŒ ะดะฐะฝะฝั‹ั… ะดะปั Hangfire
// Install-Package OutCode.EscapeTeams.ObjectRepository.Hangfire

์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋  ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

public class ParentEntity : BaseEntity
{
    public ParentEntity(Guid id) => Id = id;
}
    
public class ChildEntity : BaseEntity
{
    public ChildEntity(Guid id) => Id = id;
    public Guid ParentId { get; set; }
    public string Value { get; set; }
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ๊ฐ์ฒด ๋ชจ๋ธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

public class ParentModel : ModelBase
{
    public ParentModel(ParentEntity entity)
    {
        Entity = entity;
    }
    
    public ParentModel()
    {
        Entity = new ParentEntity(Guid.NewGuid());
    }
    
    public Guid? NullableId => null;
    
    // ะŸั€ะธะผะตั€ ัะฒัะทะธ 1:Many
    public IEnumerable<ChildModel> Children => Multiple<ChildModel>(x => x.ParentId);
    
    protected override BaseEntity Entity { get; }
}
    
public class ChildModel : ModelBase
{
    private ChildEntity _childEntity;
    
    public ChildModel(ChildEntity entity)
    {
        _childEntity = entity;
    }
    
    public ChildModel() 
    {
        _childEntity = new ChildEntity(Guid.NewGuid());
    }
    
    public Guid ParentId
    {
        get => _childEntity.ParentId;
        set => UpdateProperty(() => _childEntity.ParentId, value);
    }
    
    public string Value
    {
        get => _childEntity.Value;
        set => UpdateProperty(() => _childEntity.Value, value
    }
    
    // ะ”ะพัั‚ัƒะฟ ั ะฟะพะธัะบะพะผ ะฟะพ ะธะฝะดะตะบััƒ
    public ParentModel Parent => Single<ParentModel>(ParentId);
    
    protected override BaseEntity Entity => _childEntity;
}

๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค๋ฅผ ์œ„ํ•œ ์ €์žฅ์†Œ ํด๋ž˜์Šค ์ž์ฒด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

public class MyObjectRepository : ObjectRepositoryBase
{
    public MyObjectRepository(IStorage storage) : base(storage, NullLogger.Instance)
    {
        IsReadOnly = true; // ะ”ะปั ั‚ะตัั‚ะพะฒ, ะฟะพะทะฒะพะปัะตั‚ ะฝะต ัะพั…ั€ะฐะฝัั‚ัŒ ะธะทะผะตะฝะตะฝะธั ะฒ ะฑะฐะทัƒ
    
        AddType((ParentEntity x) => new ParentModel(x));
        AddType((ChildEntity x) => new ChildModel(x));
    
        // ะ•ัะปะธ ะธัะฟะพะปัŒะทัƒะตั‚ัั Hangfire ะธ ะฝะตะพะฑั…ะพะดะธะผะพ ั…ั€ะฐะฝะธั‚ัŒ ะผะพะดะตะปัŒ ะดะฐะฝะฝั‹ั… ะดะปั Hangfire ะฒ ObjectRepository
        // this.RegisterHangfireScheme(); 
    
        Initialize();
    }
}

ObjectRepository ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

var memory = new MemoryStream();
var db = new LiteDatabase(memory);
var dbStorage = new LiteDbStorage(db);
    
var repository = new MyObjectRepository(dbStorage);
await repository.WaitForInitialize();

ํ”„๋กœ์ ํŠธ๊ฐ€ HangFire๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ

public void ConfigureServices(IServiceCollection services, ObjectRepository objectRepository)
{
    services.AddHangfire(s => s.UseHangfireStorage(objectRepository));
}

์ƒˆ ๊ฐœ์ฒด ์‚ฝ์ž…:

var newParent = new ParentModel()
repository.Add(newParent);

์ด ํ˜ธ์ถœ์„ ํ†ตํ•ด ๊ฐ์ฒด๋Š” ์ƒ์œ„ ๋ชจ๋ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์“ฐ๊ธฐ ์œ„ํ•ด ๋กœ์ปฌ ์บ์‹œ์™€ ํ ๋ชจ๋‘์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ์ž‘์—…์—๋Š” O(1)์ด ์†Œ์š”๋˜๋ฉฐ ์ด ๊ฐœ์ฒด๋ฅผ ์ฆ‰์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ €์žฅ์†Œ์—์„œ ์ด ๊ฐ์ฒด๋ฅผ ์ฐพ๊ณ  ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด๊ฐ€ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค์ธ์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

var parents = repository.Set<ParentModel>();
var myParent = parents.Find(newParent.Id);
Assert.IsTrue(ReferenceEquals(myParent, newParent));

๋ฌด์Šจ ์ผ์ด์•ผ? ์„ธํŠธ () ๋ฐ˜ํ™˜ ํ…Œ์ด๋ธ”์‚ฌ์ „, ํฌํ•จํ•˜๋Š” ๋™์‹œ์‚ฌ์ „ ๊ธฐ๋ณธ ๋ฐ ๋ณด์กฐ ์ธ๋ฑ์Šค์˜ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ๊ฐœ์ฒด๋ฅผ ์™„์ „ํžˆ ๋ฐ˜๋ณตํ•˜์ง€ ์•Š๊ณ ๋„ ID(๋˜๋Š” ๊ธฐํƒ€ ์ž„์˜์˜ ์‚ฌ์šฉ์ž ์ธ๋ฑ์Šค)๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ๊ฐœ์ฒด ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ๋…์ด ์ถ”๊ฐ€๋˜๋ฏ€๋กœ ์†์„ฑ์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ด ๊ฐœ์ฒด๋„ ์“ฐ๊ธฐ ๋Œ€๊ธฐ์—ด์— ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. 
์™ธ๋ถ€์—์„œ ์†์„ฑ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์€ POCO ๊ฐœ์ฒด๋กœ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

myParent.Children.First().Property = "Updated value";

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

repository.Remove(myParent);
repository.RemoveRange(otherParents);
repository.Remove<ParentModel>(x => !x.Children.Any());

๊ทธ๋Ÿฌ๋ฉด ๊ฐœ์ฒด๊ฐ€ ์‚ญ์ œ ๋Œ€๊ธฐ์—ด์—๋„ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

์ €์žฅ์€ ์–ด๋–ป๊ฒŒ ์ด๋ฃจ์–ด์ง€๋‚˜์š”?

๊ฐœ์ฒด ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ชจ๋‹ˆํ„ฐ๋ง๋˜๋Š” ๊ฐ์ฒด๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด(์†์„ฑ ์ถ”๊ฐ€, ์‚ญ์ œ ๋˜๋Š” ๋ณ€๊ฒฝ) ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ธ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.๊ตฌ๋…ํ•˜๋‹ค I์ €์žฅ. ๊ตฌํ˜„ I์ €์žฅ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋ชจ๋ธ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ์ถ”๊ฐ€, ์—…๋ฐ์ดํŠธ, ์‚ญ์ œ ๋“ฑ 3๊ฐœ์˜ ๋Œ€๊ธฐ์—ด์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๊ตฌํ˜„ I์ €์žฅ ์ดˆ๊ธฐํ™” ์‹œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด 5์ดˆ๋งˆ๋‹ค ์ €์žฅ๋˜๋„๋ก ํ•˜๋Š” ํƒ€์ด๋จธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. 

๋˜ํ•œ ์ €์žฅ ํ˜ธ์ถœ์„ ๊ฐ•์ œํ•˜๋Š” API๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ์ฒด์ €์žฅ์†Œ.์ €์žฅ().

๊ฐ ์ €์žฅ ์ „์— ๋จผ์ € ์˜๋ฏธ ์—†๋Š” ์ž‘์—…์ด ๋Œ€๊ธฐ์—ด์—์„œ ์ œ๊ฑฐ๋˜๊ณ (์˜ˆ: ์ค‘๋ณต ์ด๋ฒคํŠธ - ๊ฐœ์ฒด๊ฐ€ ๋‘ ๋ฒˆ ๋ณ€๊ฒฝ๋˜๊ฑฐ๋‚˜ ๊ฐœ์ฒด๊ฐ€ ๋น ๋ฅด๊ฒŒ ์ถ”๊ฐ€/์ œ๊ฑฐ๋œ ๊ฒฝ์šฐ) ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ €์žฅ ์ž์ฒด๋งŒ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. 

๋ชจ๋“  ๊ฒฝ์šฐ์— ์ „์ฒด ํ˜„์žฌ ๊ฐœ์ฒด๊ฐ€ ์ €์žฅ๋˜๋ฏ€๋กœ ๊ฐœ์ฒด๊ฐ€ ๋Œ€๊ธฐ์—ด์— ์ถ”๊ฐ€๋œ ์‹œ์ ๋ณด๋‹ค ์ตœ์‹  ๋ฒ„์ „์˜ ๊ฐœ์ฒด๋ฅผ ํฌํ•จํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ์ˆœ์„œ์™€ ๋‹ค๋ฅธ ์ˆœ์„œ๋กœ ๊ฐœ์ฒด๊ฐ€ ์ €์žฅ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ ๋ฌด์—‡์ด ์žˆ๋‚˜์š”?

  • ๋ชจ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” .NET Standard 2.0์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ตœ์‹  .NET ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • API๋Š” ์Šค๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ถ€ ์ปฌ๋ ‰์…˜์€ ๋‹ค์Œ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ๋™์‹œ์‚ฌ์ „, ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—๋Š” ์ž ๊ธˆ์ด ์žˆ๊ฑฐ๋‚˜ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. 
    ๊ธฐ์–ตํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š” ์œ ์ผํ•œ ๊ฒƒ์€ ์ „ํ™”ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค ObjectRepository.Save();
  • ์ž„์˜ ์ธ๋ฑ์Šค(๊ณ ์œ ์„ฑ ํ•„์š”):

repository.Set<ChildModel>().AddIndex(x => x.Value);
repository.Set<ChildModel>().Find(x => x.Value, "myValue");

๋ˆ„๊ฐ€ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ?

๊ฐœ์ธ์ ์œผ๋กœ ์ €๋Š” ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ๋ชจ๋“  ์ทจ๋ฏธ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ํŽธ๋ฆฌํ•˜๊ณ  ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ๊ณ„์ธต์„ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ๋ฌด๊ฑฐ์šด ์ธํ”„๋ผ๋ฅผ ๋ฐฐํฌํ•˜๋Š” ๋ฐ ํฐ ๋น„์šฉ์ด ๋“ค์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ litdb๋‚˜ ํŒŒ์ผ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. 

ํ•˜์ง€๋งŒ ๊ณผ๊ฑฐ์—๋Š” ์ง€๊ธˆ์€ ์—†์–ด์ง„ ์Šคํƒ€ํŠธ์—…์ธ EscapeTeams(์—ฌ๊ธฐ์— ๋ˆ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ์•„๋‹ˆ, ๋‹ค์‹œ ๊ฒฝํ—˜ํ•ด ๋ณด์„ธ์š”) - Azure Table Storage์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์•ž์œผ๋กœ์˜ ๊ณ„ํš

์ด ์ ‘๊ทผ ๋ฐฉ์‹์˜ ์ฃผ์š” ๋‹จ์  ์ค‘ ํ•˜๋‚˜์ธ ์ˆ˜ํ‰ ํ™•์žฅ์„ ์ˆ˜์ •ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ ค๋ฉด ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜(sic!)์ด ํ•„์š”ํ•˜๊ฑฐ๋‚˜, ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค์˜ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๋Š” ๊ฐ•๋ ฅํ•œ ์˜์ง€์˜ ๊ฒฐ์ •์„ ๋‚ด๋ฆฌ๊ฑฐ๋‚˜, "๋งˆ์ง€๋ง‰ ์‚ฌ๋žŒ์ด ์˜ณ๋‹ค"๋Š” ์›์น™์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ๋˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ์ˆ ์  ๊ด€์ ์—์„œ ๋ณผ ๋•Œ ๊ฐ€๋Šฅํ•œ ๋‹ค์Œ ๊ตฌ์„ฑํ‘œ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

  • ๊ฐœ์ฒด ๋ชจ๋ธ ๋Œ€์‹  EventLog ๋ฐ Snapshot ์ €์žฅ
  • ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค ์ฐพ๊ธฐ(๋ชจ๋“  ์ธ์Šคํ„ด์Šค์˜ ์—”๋“œํฌ์ธํŠธ๋ฅผ ์„ค์ •? udp ๊ฒ€์ƒ‰? ๋งˆ์Šคํ„ฐ/์Šฌ๋ ˆ์ด๋ธŒ?์— ์ถ”๊ฐ€)
  • RAFT์™€ ๊ฐ™์€ ํ•ฉ์˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•ด EventLog ์ธ์Šคํ„ด์Šค ๊ฐ„ ๋ณต์ œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ œ๊ฐ€ ๊ฑฑ์ •ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณ„๋‹จ์‹ ์‚ญ์ œ ๋˜๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด์™€ ๋งํฌ๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด ์‚ญ์ œ ์‚ฌ๋ก€ ๊ฐ์ง€์ž…๋‹ˆ๋‹ค. 

์†Œ์Šค ์ฝ”๋“œ

์—ฌ๊ธฐ๊นŒ์ง€ ์ฝ์—ˆ๋‹ค๋ฉด ์ด์ œ ๋‚จ์€ ๊ฒƒ์€ ์ฝ”๋“œ๋ฅผ ์ฝ๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” GitHub์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
https://github.com/DiverOfDark/ObjectRepository

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€