ObjectRepository β€” .NET in-memory repository pattern Π·Π° Π²Π°ΡˆΠΈΡ‚Π΅ домашни ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈ

Π—Π°Ρ‰ΠΎ Π΄Π° ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π°Ρ‚Π΅ всичкитС Π΄Π°Π½Π½ΠΈ Π² ΠΏΠ°ΠΌΠ΅Ρ‚Ρ‚Π°?

ΠŸΡ€ΠΈ ΡΡŠΡ…Ρ€Π°Π½Π΅Π½ΠΈΠ΅ Π½Π° Π΄Π°Π½Π½ΠΈ Π·Π° сайта ΠΈΠ»ΠΈ Π±Π΅ΠΊΠ΅Π½Π΄Π°, ΠΏΠΎΠ²Π΅Ρ‡Π΅Ρ‚ΠΎ Ρ€Π°Π·ΡƒΠΌΠ½ΠΈ Ρ…ΠΎΡ€Π° ΠΏΡŠΡ€Π²ΠΎ Ρ‰Π΅ ΠΈΠ·Π±Π΅Ρ€Π°Ρ‚ SQL Π±Π°Π·Π° Π΄Π°Π½Π½ΠΈ.Β 

Но понякога Π² Π³Π»Π°Π²Π°Ρ‚Π° възниква ΠΌΠΈΡΡŠΠ»Ρ‚Π°, Ρ‡Π΅ ΠΌΠΎΠ΄Π΅Π»ΡŠΡ‚ Π½Π° Π΄Π°Π½Π½ΠΈ Π½Π΅ Π΅ подходящ Π·Π° SQL: Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΏΡ€ΠΈ ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ Π½Π° Ρ‚ΡŠΡ€ΡΠ΅Π½Π΅ ΠΈΠ»ΠΈ социална Π³Ρ€Π°Ρ„ΠΈΠΊΠ°, Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠ° Ρ‚ΡŠΡ€ΡΠ΅Π½Π΅ ΠΏΠΎ слоТни Π²Ρ€ΡŠΠ·ΠΊΠΈ ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΎΠ±Π΅ΠΊΡ‚ΠΈΡ‚Π΅.Β 

Най-Π»ΠΎΡˆΠ°Ρ‚Π° ситуация Π΅, ΠΊΠΎΠ³Π°Ρ‚ΠΎ Ρ€Π°Π±ΠΎΡ‚ΠΈΡ‚Π΅ Π² Π΅ΠΊΠΈΠΏ ΠΈ ΠΊΠΎΠ»Π΅Π³Π° Π½Π΅ Π·Π½Π°Π΅ ΠΊΠ°ΠΊ Π΄Π° ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π° Π±ΡŠΡ€Π·ΠΈ заявки. Колко Π²Ρ€Π΅ΠΌΠ΅ стС ΠΏΡ€Π΅ΠΊΠ°Ρ€Π°Π»ΠΈ Π·Π° Ρ€Π΅ΡˆΠ°Π²Π°Π½Π΅ Π½Π° ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ N+1 ΠΈ ΠΈΠ·Π³Ρ€Π°ΠΆΠ΄Π°Π½Π΅ Π½Π° Π΄ΠΎΠΏΡŠΠ»Π½ΠΈΡ‚Π΅Π»Π½ΠΈ индСкси, Π·Π° Π΄Π° SELECT Π½Π° Π³Π»Π°Π²Π½Π°Ρ‚Π° страница Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈ Π·Π° Ρ€Π°Π·ΡƒΠΌΠ½ΠΎ Π²Ρ€Π΅ΠΌΠ΅?

Π”Ρ€ΡƒΠ³ популярСн ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Π΅ NoSQL. ΠŸΡ€Π΅Π΄ΠΈ няколко Π³ΠΎΠ΄ΠΈΠ½ΠΈ имашС голям ΡˆΡƒΠΌ ΠΎΠΊΠΎΠ»ΠΎ Ρ‚Π°Π·ΠΈ Ρ‚Π΅ΠΌΠ° - Π·Π° всяка ΡƒΠ΄ΠΎΠ±Π½Π° Π²ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ Ρ€Π°Π·Π³Ρ€ΡŠΡ‰Π°Ρ…Π° MongoDB ΠΈ сС Ρ€Π°Π΄Π²Π°Ρ…Π° Π½Π° ΠΎΡ‚Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚Π΅ ΠΏΠΎΠ΄ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° Π½Π° json-Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΈ (ΠΌΠ΅ΠΆΠ΄Ρƒ Π΄Ρ€ΡƒΠ³ΠΎΡ‚ΠΎ, ΠΊΠΎΠ»ΠΊΠΎ ΠΌΠ½ΠΎΠ³ΠΎ "костилки" Ρ‚Ρ€ΡΠ±Π²Π°ΡˆΠ΅ Π΄Π° слоТитС Π·Π°Ρ€Π°Π΄ΠΈ Ρ†ΠΈΠΊΠ»ΠΈΡ‡Π½ΠΈΡ‚Π΅ Π²Ρ€ΡŠΠ·ΠΊΠΈ Π² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΈΡ‚Π΅?).

ΠŸΡ€Π΅Π΄Π»Π°Π³Π°ΠΌ Π΄Π° ΠΎΠΏΠΈΡ‚Π°Ρ‚Π΅ ΠΎΡ‰Π΅ Π΅Π΄ΠΈΠ½, Π°Π»Ρ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π΅Π½ Π½Π°Ρ‡ΠΈΠ½ - Π·Π°Ρ‰ΠΎ Π΄Π° Π½Π΅ ΠΎΠΏΠΈΡ‚Π°Ρ‚Π΅ Π΄Π° ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π°Ρ‚Π΅ всичкитС Π΄Π°Π½Π½ΠΈ Π² ΠΏΠ°ΠΌΠ΅Ρ‚Ρ‚Π° Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ, ΠΏΠ΅Ρ€ΠΈΠΎΠ΄ΠΈΡ‡Π½ΠΎ Π·Π°ΠΏΠ°Π·Π²Π°ΠΉΠΊΠΈ Π² ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»Π½ΠΎ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ (Ρ„Π°ΠΉΠ», ΠΎΡ‚Π΄Π°Π»Π΅Ρ‡Π΅Π½Π° Π±Π°Π·Π° Π΄Π°Π½Π½ΠΈ)?Β 

ΠŸΠ°ΠΌΠ΅Ρ‚Ρ‚Π° стана Π΅Π²Ρ‚ΠΈΠ½Π°, Π° ΠΏΠΎΠ²Π΅Ρ‡Π΅Ρ‚ΠΎ възмоТни Π΄Π°Π½Π½ΠΈ Π½Π° ΠΏΠΎΠ²Π΅Ρ‡Π΅Ρ‚ΠΎ ΠΌΠ°Π»ΠΊΠΈ ΠΈ срСдни ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈ Π²Π»ΠΈΠ·Π°Ρ‚ Π² 1 GB ΠΏΠ°ΠΌΠ΅Ρ‚. (НапримСр, Π»ΡŽΠ±ΠΈΠΌΠΈΡΡ‚ ΠΌΠΈ домашСн ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ - финансов Ρ‚Ρ€Π΅ΠΊΠ΅Ρ€, ΠΊΠΎΠΉΡ‚ΠΎ Π²ΠΎΠ΄ΠΈ Π΅ΠΆΠ΅Π΄Π½Π΅Π²Π½Π° статистика ΠΈ история Π½Π° ΠΌΠΎΠΈΡ‚Π΅ Ρ€Π°Π·Ρ…ΠΎΠ΄ΠΈ, баланси ΠΈ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ Π·Π° Π³ΠΎΠ΄ΠΈΠ½Π° ΠΈ ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½Π°, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° само 45 MB ΠΏΠ°ΠΌΠ΅Ρ‚.)

ΠŸΡ€Π΅Π΄ΠΈΠΌΡΡ‚Π²Π°:

  • Π”ΠΎΡΡ‚ΡŠΠΏΡŠΡ‚ Π΄ΠΎ Π΄Π°Π½Π½ΠΈΡ‚Π΅ става ΠΏΠΎ-лСсСн - Π½Π΅ Π΅ Π½ΡƒΠΆΠ½ΠΎ Π΄Π° сС притСсняватС Π·Π° заявки, Π»Π΅Π½ΠΈΠ²ΠΎ Π·Π°Ρ€Π΅ΠΆΠ΄Π°Π½Π΅, особСности Π½Π° 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:Много
    public IEnumerable Children => Multiple(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(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);

ΠŸΡ€ΠΈ Ρ‚ΠΎΠ·ΠΈ Π²ΠΈΠΊ ΠΎΠ±Π΅ΠΊΡ‚ΡŠΡ‚ ParentModel сС добавя ΠΊΠ°ΠΊΡ‚ΠΎ Π² локалния кСш, Ρ‚Π°ΠΊΠ° ΠΈ Π² ΠΎΠΏΠ°ΡˆΠΊΠ°Ρ‚Π° Π·Π° запис Π² Π±Π°Π·Π°Ρ‚Π°. Π—Π°Ρ‚ΠΎΠ²Π° Ρ‚Π°Π·ΠΈ опСрация Π·Π°Π΅ΠΌΠ° O(1) ΠΈ ΠΌΠΎΠΆΠ΅ΠΌ Π²Π΅Π΄Π½Π°Π³Π° Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈΠΌ с Ρ‚ΠΎΠ·ΠΈ ΠΎΠ±Π΅ΠΊΡ‚.

НапримСр, Π·Π° Π΄Π° Π½Π°ΠΌΠ΅Ρ€ΠΈΠΌ Ρ‚ΠΎΠ·ΠΈ ΠΎΠ±Π΅ΠΊΡ‚ Π² рСпозитория ΠΈ Π΄Π° сС ΡƒΠ²Π΅Ρ€ΠΈΠΌ, Ρ‡Π΅ Π²ΡŠΡ€Π½Π°Ρ‚ΠΈΡΡ‚ ΠΎΠ±Π΅ΠΊΡ‚ Π΅ ΡΡŠΡ‰ΠΈΡΡ‚ СкзСмпляр:

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

Какво сС случва Π² Ρ‚ΠΎΠ·ΠΈ случай? Set() Π²ΡŠΡ€Ρ‰Π° TableDictionary, ΠΊΠΎΠΉΡ‚ΠΎ ΡΡŠΠ΄ΡŠΡ€ΠΆΠ° ConcurrentDictionary ΠΈ прСдоставя Π΄ΠΎΠΏΡŠΠ»Π½ΠΈΡ‚Π΅Π»Π΅Π½ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π» Π·Π° основни ΠΈ Π²Ρ‚ΠΎΡ€ΠΈΡ‡Π½ΠΈ индСкси. Π’ΠΎΠ²Π° позволява Π΄Π° ΠΈΠΌΠ°ΠΌΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΈ Π·Π° Ρ‚ΡŠΡ€ΡΠ΅Π½Π΅ ΠΏΠΎ Id (ΠΈΠ»ΠΈ Π΄Ρ€ΡƒΠ³ΠΈ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»Π½ΠΈ потрСбитСлски индСкси) Π±Π΅Π· Π΄Π° Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ пълно ΠΏΡ€Π΅Π³Π»Π΅ΠΆΠ΄Π°Π½Π΅ Π½Π° всички ΠΎΠ±Π΅ΠΊΡ‚ΠΈ.

ΠŸΡ€ΠΈ добавянС Π½Π° ΠΎΠ±Π΅ΠΊΡ‚ΠΈ Π² ObjectRepository сС добавя подписка Π·Π° измСнСния Π½Π° Ρ‚Π΅Ρ…Π½ΠΈΡ‚Π΅ свойства, Ρ‚Π°ΠΊΠ° Ρ‡Π΅ всяка промяна Π½Π° свойствата ΡΡŠΡ‰ΠΎ Π²ΠΎΠ΄ΠΈ Π΄ΠΎ добавянСто Π½Π° Ρ‚ΠΎΠ·ΠΈ ΠΎΠ±Π΅ΠΊΡ‚ Π² ΠΎΠΏΠ°ΡˆΠΊΠ°Ρ‚Π° Π·Π° запис.Β 
ΠžΠ±Π½ΠΎΠ²ΡΠ²Π°Π½Π΅Ρ‚ΠΎ Π½Π° свойствата ΠΎΡ‚Π²ΡŠΠ½ ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π° ΠΏΠΎ ΡΡŠΡ‰ΠΈΡ Π½Π°Ρ‡ΠΈΠ½, ΠΊΠ°ΠΊΡ‚ΠΎ ΠΈ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° с POCO ΠΎΠ±Π΅ΠΊΡ‚:

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

ΠžΠ±Π΅ΠΊΡ‚ΡŠΡ‚ ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС ΠΏΡ€Π΅ΠΌΠ°Ρ…Π½Π°Ρ‚ ΠΏΠΎ слСднитС Π½Π°Ρ‡ΠΈΠ½ΠΈ:

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

ΠŸΡ€ΠΈ Ρ‚ΠΎΠ²Π° ΡΡŠΡ‰ΠΎ сС добавя ΠΎΠ±Π΅ΠΊΡ‚ΡŠΡ‚ Π² ΠΎΠΏΠ°ΡˆΠΊΠ°Ρ‚Π° Π·Π° ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅.

Как Ρ€Π°Π±ΠΎΡ‚ΠΈ Π·Π°ΠΏΠ°Π·Π²Π°Π½Π΅Ρ‚ΠΎ?

ObjectRepository ΠΏΡ€ΠΈ промяна Π½Π° прослСдяванитС ΠΎΠ±Π΅ΠΊΡ‚ΠΈ (ΠΊΠ°ΠΊΡ‚ΠΎ добавянС ΠΈΠ»ΠΈ ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅, Ρ‚Π°ΠΊΠ° ΠΈ промяна Π½Π° свойства) ΠΏΡ€Π΅Π΄ΠΈΠ·Π²ΠΈΠΊΠ²Π° ΡΡŠΠ±ΠΈΡ‚ΠΈΠ΅ ModelChanged, Π½Π° ΠΊΠΎΠ΅Ρ‚ΠΎ Π΅ Π°Π±ΠΎΠ½ΠΈΡ€Π°Π½ IStorage. Π Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈΡ‚Π΅ IStorage ΠΏΡ€ΠΈ възникванС Π½Π° ΡΡŠΠ±ΠΈΡ‚ΠΈΠ΅Ρ‚ΠΎ ModelChanged ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π°Ρ‚ ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅ Π² 3 опашки β€” Π·Π° добавянС, Π·Π° обновяванС ΠΈ Π·Π° ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅.

Π‘ΡŠΡ‰ΠΎ Ρ‚Π°ΠΊΠ° Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈΡ‚Π΅ IStorage ΠΏΡ€ΠΈ инициализация ΡΡŠΠ·Π΄Π°Π²Π°Ρ‚ Ρ‚Π°ΠΉΠΌΠ΅Ρ€, ΠΊΠΎΠΉΡ‚ΠΎ Π½Π° всСки 5 сСкунди ΠΈΠ·Π²ΠΈΠΊΠ²Π° Π·Π°ΠΏΠ°Π·Π²Π°Π½Π΅Ρ‚ΠΎ Π½Π° ΠΏΡ€ΠΎΠΌΠ΅Π½ΠΈΡ‚Π΅.Β 

ОсвСн Ρ‚ΠΎΠ²Π° ΠΈΠΌΠ° API Π·Π° ΠΏΡ€ΠΈΠ½ΡƒΠ΄ΠΈΡ‚Π΅Π»Π½ΠΎ ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½Π΅ Π½Π° Π·Π°ΠΏΠ°Π·Π²Π°Π½Π΅: ObjectRepository.Save().

ΠŸΡ€Π΅Π΄ΠΈ всяко Π·Π°ΠΏΠ°Π·Π²Π°Π½Π΅ ΠΏΡŠΡ€Π²ΠΎ сС ΠΈΠ·Π²ΡŠΡ€ΡˆΠ²Π° ΠΏΡ€Π΅ΠΌΠ°Ρ…Π²Π°Π½Π΅ ΠΎΡ‚ ΠΎΠΏΠ°ΡˆΠΊΠΈΡ‚Π΅ Π½Π° бСзсмислСни ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π΄ΡƒΠ±Π»ΠΈΠΊΠ°Ρ‚ΠΈ Π½Π° ΡΡŠΠ±ΠΈΡ‚ΠΈΡ β€” ΠΊΠΎΠ³Π°Ρ‚ΠΎ ΠΎΠ±Π΅ΠΊΡ‚ΡŠΡ‚ Π΅ Π±ΠΈΠ» промСнян Π΄Π²Π° ΠΏΡŠΡ‚ΠΈ ΠΈΠ»ΠΈ Π±ΡŠΡ€Π·ΠΎ добавянС/ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅ Π½Π° ΠΎΠ±Π΅ΠΊΡ‚ΠΈ) ΠΈ Π΅Π΄Π²Π° слСд Ρ‚ΠΎΠ²Π° самото Π·Π°ΠΏΠ°Π·Π²Π°Π½Π΅.Β 

Π’ΡŠΠ² всички случаи сС Π·Π°ΠΏΠ°Π·Π²Π° актуалният ΠΎΠ±Π΅ΠΊΡ‚ изцяло, Π·Π°Ρ‚ΠΎΠ²Π° Π΅ възмоТна ситуация, ΠΏΡ€ΠΈ която ΠΎΠ±Π΅ΠΊΡ‚ΠΈΡ‚Π΅ сС Π·Π°ΠΏΠ°Π·Π²Π°Ρ‚ Π² Ρ€Π°Π·Π»ΠΈΡ‡Π΅Π½ Ρ€Π΅Π΄ ΠΎΡ‚ Ρ‚ΠΎΠ·ΠΈ, ΠΏΠΎ ΠΊΠΎΠΉΡ‚ΠΎ са Π±ΠΈΠ»ΠΈ промСняни, Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»Π½ΠΎ ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° сС Π·Π°ΠΏΠ°Π·Π²Π°Ρ‚ ΠΏΠΎ-Π½ΠΎΠ²ΠΈ вСрсии Π½Π° ΠΎΠ±Π΅ΠΊΡ‚ΠΈΡ‚Π΅, ΠΎΡ‚ΠΊΠΎΠ»ΠΊΠΎΡ‚ΠΎ Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° Π½Π° добавянС Π² ΠΎΠΏΠ°ΡˆΠΊΠ°Ρ‚Π°.

Какво ΠΎΡ‰Π΅ ΠΈΠΌΠ°?

  • Всички Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ са основани Π½Π° .NET Standard 2.0. ΠœΠΎΠ³Π°Ρ‚ Π΄Π° сС ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚ Π² ΠΊΠΎΠΉΡ‚ΠΎ ΠΈ Π΄Π° Π΅ ΡΡŠΠ²Ρ€Π΅ΠΌΠ΅Π½Π΅Π½ .NET ΠΏΡ€ΠΎΠ΅ΠΊΡ‚.
  • API Π΅ потокобСзопасСн. Π’ΡŠΡ‚Ρ€Π΅ΡˆΠ½ΠΈΡ‚Π΅ ΠΊΠΎΠ»Π΅ΠΊΡ†ΠΈΠΈ са Ρ€Π΅Π°Π»ΠΈΠ·ΠΈΡ€Π°Π½ΠΈ Π½Π° Π±Π°Π·Π° ConcurrentDictionary, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΡ†ΠΈΡ‚Π΅ Π½Π° ΡΡŠΠ±ΠΈΡ‚ΠΈΡ ΠΈΠΌΠ°Ρ‚ ΠΈΠ»ΠΈ Π·Π°ΠΊΠ»ΡŽΡ‡Π²Π°Π½ΠΈΡ, ΠΈΠ»ΠΈ Π½Π΅ сС нуТдаят ΠΎΡ‚ тях.Β 
    ЕдинствСното, ΠΊΠΎΠ΅Ρ‚ΠΎ трябва Π΄Π° ΠΏΠΎΠΌΠ½ΠΈΡ‚Π΅, Π΅, Ρ‡Π΅ ΠΏΡ€ΠΈ ΠΏΡ€ΠΈΠΊΠ»ΡŽΡ‡Π²Π°Π½Π΅ Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅Ρ‚ΠΎ трябва Π΄Π° ΠΈΠ·Π²ΠΈΠΊΠ°Ρ‚Π΅ ObjectRepository.Save();
  • ΠŸΡ€ΠΎΠΈΠ·Π²ΠΎΠ»Π½ΠΈ индСкси (изискват уникалност):

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

Кой го използва?

Π›ΠΈΡ‡Π½ΠΎ Π°Π· Π·Π°ΠΏΠΎΡ‡Π½Π°Ρ… Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌ Ρ‚ΠΎΠ·ΠΈ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ във всички Ρ…ΠΎΠ±ΠΈΠΉΠ½ΠΈ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈ, Ρ‚ΡŠΠΉ ΠΊΠ°Ρ‚ΠΎ Π΅ ΡƒΠ΄ΠΎΠ±Π΅Π½ ΠΈ Π½Π΅ изисква Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»Π½ΠΈ Ρ€Π°Π·Ρ…ΠΎΠ΄ΠΈ Π·Π° писанС Π½Π° слой Π·Π° Π΄ΠΎΡΡ‚ΡŠΠΏ Π΄ΠΎ Π΄Π°Π½Π½ΠΈ ΠΈΠ»ΠΈ Ρ€Π°Π·Π²ΠΈΠ²Π°Π½Π΅ Π½Π° Ρ‚Π΅ΠΆΠΊΠ° инфраструктура. Π—Π° ΠΌΠ΅Π½ ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΎ Π΅ Π΄ΠΎΡΡ‚Π°Ρ‚ΡŠΡ‡Π½ΠΎ Π΄Π° ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π°ΠΌ Π΄Π°Π½Π½ΠΈ Π² litedb ΠΈΠ»ΠΈ Ρ„Π°ΠΉΠ».Β 

Но Π² ΠΌΠΈΠ½Π°Π»ΠΎΡ‚ΠΎ, ΠΊΠΎΠ³Π°Ρ‚ΠΎ с Π΅ΠΊΠΈΠΏΠ° ΡΡŠΠ·Π΄Π°Π²Π°Ρ…ΠΌΠ΅ сСга нСработСщия стартап EscapeTeams (мислСх, Π΅Ρ‚ΠΎ Π³ΠΈ, ΠΏΠ°Ρ€ΠΈΡ‚Π΅ β€” Π° Π½Π΅, ΠΎΡ‚Π½ΠΎΠ²ΠΎ ΠΎΠΏΠΈΡ‚) β€” ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ…ΠΌΠ΅ Azure Table Storage Π·Π° ΡΡŠΡ…Ρ€Π°Π½Π΅Π½ΠΈΠ΅ Π½Π° Π΄Π°Π½Π½ΠΈ.

ПлановС Π·Π° Π±ΡŠΠ΄Π΅Ρ‰Π΅Ρ‚ΠΎ

Искам Π΄Π° поправя Π΅Π΄ΠΈΠ½ ΠΎΡ‚ основнитС Π½Π΅Π΄ΠΎΡΡ‚Π°Ρ‚ΡŠΡ†ΠΈ Π½Π° Ρ‚ΠΎΠ·ΠΈ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ β€” Ρ…ΠΎΡ€ΠΈΠ·ΠΎΠ½Ρ‚Π°Π»Π½ΠΎΡ‚ΠΎ ΠΌΠ°Ρ‰Π°Π±ΠΈΡ€Π°Π½Π΅. Π—Π° Ρ‚ΠΎΠ²Π° са Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΈ ΠΈΠ»ΠΈ Ρ€Π°Π·ΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ (sic!), ΠΈΠ»ΠΈ Π΄Π° сС Π²Π·Π΅ΠΌΠ΅ Π²ΠΎΠ»Π΅Π²ΠΎ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅, Ρ‡Π΅ ΡΡŠΡ‰ΠΈΡ‚Π΅ Π΄Π°Π½Π½ΠΈ ΠΎΡ‚ Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ инстанции Π½Π΅ трябва Π΄Π° сС промСнят, ΠΈΠ»ΠΈ Π΄Π° сС промСнят ΠΏΠΎ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ° β€žΠΊΠΎΠΉ послСдСн, Ρ‚ΠΎΠΉ ΠΈ ΠΏΡ€Π°Π²β€œ.

ΠžΡ‚ тСхничСска Π³Π»Π΅Π΄Π½Π° Ρ‚ΠΎΡ‡ΠΊΠ° Π²ΠΈΠΆΠ΄Π°ΠΌ слСдната схСма:

  • Π”Π° сС ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π° вмСсто ΠΎΠ±Π΅ΠΊΡ‚Π½Π° ΠΌΠΎΠ΄Π΅Π» EventLog ΠΈ Snapshot
  • Π”Π° сС Π½Π°ΠΌΠΈΡ€Π°Ρ‚ Π΄Ρ€ΡƒΠ³ΠΈ инстанции (Π΄Π° сС добавят Π² настройкитС ΠΊΡ€Π°ΠΉΠ½ΠΈ Ρ‚ΠΎΡ‡ΠΊΠΈ Π½Π° всички инстанции? UDP ΠΎΡ‚ΠΊΡ€ΠΈΡ‚ΠΈΠ΅? master/slave?)
  • Π”Π° сС Ρ€Π΅ΠΏΠ»ΠΈΠΊΠΈΡ€Π° ΠΌΠ΅ΠΆΠ΄Ρƒ инстанциитС EventLog Ρ‡Ρ€Π΅Π· ΠΊΠΎΠΉΡ‚ΠΎ ΠΈ Π΄Π° Π΅ ΠΎΡ‚ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠΈΡ‚Π΅ Π·Π° консСнсус, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ RAFT.

Π‘ΡŠΡ‰Π΅ΡΡ‚Π²ΡƒΠ²Π° ΠΈ ΠΎΡ‰Π΅ Π΅Π΄ΠΈΠ½ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, ΠΊΠΎΠΉΡ‚ΠΎ ΠΌΠ΅ притСснява β€” каскадното ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅, ΠΈΠ»ΠΈ ΠΎΡ‚ΠΊΡ€ΠΈΡ‚ΠΈΠ΅ Π½Π° случаи Π½Π° ΠΈΠ·Ρ‚Ρ€ΠΈΠ²Π°Π½Π΅ Π½Π° ΠΎΠ±Π΅ΠΊΡ‚ΠΈ, Π½Π° ΠΊΠΎΠΈΡ‚ΠΎ ΠΈΠΌΠ° ΠΏΡ€Π΅ΠΏΡ€Π°Ρ‚ΠΊΠΈ ΠΎΡ‚ Π΄Ρ€ΡƒΠ³ΠΈ ΠΎΠ±Π΅ΠΊΡ‚ΠΈ.Β 

Π˜Π·Ρ…ΠΎΠ΄Π΅Π½ ΠΊΠΎΠ΄

Ако стС ΠΏΡ€ΠΎΡ‡Π΅Π»ΠΈ Π΄ΠΎ Ρ‚ΡƒΠΊ β€” останалото Π΅ само ΠΊΠΎΠ΄, ΠΊΠΎΠΉΡ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π½Π°ΠΌΠ΅Ρ€ΠΈΡ‚Π΅ Π½Π° GitHub:
https://github.com/DiverOfDark/ObjectRepository

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС с Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ πŸ”₯ ΠšΡƒΠΏΠ΅Ρ‚Π΅ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ хостинг Π·Π° сайтовС с Π·Π°Ρ‰ΠΈΡ‚Π° ΠΎΡ‚ DDoS, VPS VDS ΡΡŠΡ€Π²ΡŠΡ€ΠΈ | ProHoster