ObjectRepository - pàtran tasgaidh cuimhneachaidh .NET airson do phròiseactan dachaigh

Carson a stòradh an dàta gu lèir mar chuimhneachan?

Gus dàta làrach-lìn no cùl-taic a stòradh, is e a’ chiad mhiann aig a’ mhòr-chuid de dhaoine ciallach stòr-dàta SQL a thaghadh. 

Ach uaireannan thig an inntinn gu inntinn nach eil am modail dàta freagarrach airson SQL: mar eisimpleir, nuair a bhios tu a ’togail graf rannsachaidh no sòisealta, feumaidh tu dàimhean iom-fhillte a lorg eadar nithean. 

Is e an suidheachadh as miosa nuair a bhios tu ag obair ann an sgioba agus nach eil fios aig co-obraiche ciamar a thogas tu fiosan sgiobalta. Dè an ùine a chuir thu seachad a’ fuasgladh dhuilgheadasan N+1 agus a’ togail chlàran-amais a bharrachd gus an crìochnaich an SELECT air a’ phrìomh dhuilleag ann an ùine reusanta?

Is e dòigh-obrach mòr-chòrdte eile NoSQL. O chionn grunn bhliadhnaichean bha tòrr hype timcheall air a’ chuspair seo - airson àm iomchaidh sam bith chuir iad MongoDB an sàs agus bha iad toilichte leis na freagairtean ann an cruth sgrìobhainnean json (co-dhiù, cia mheud crutches a dh’ fheumadh tu a chuir a-steach air sgàth nan ceanglaichean cruinn anns na sgrìobhainnean?).

Tha mi a’ moladh dòigh eile, eile fheuchainn - carson nach feuch thu an dàta gu lèir a stòradh ann an cuimhne an tagraidh, bho àm gu àm ga shàbhaladh gu stòradh air thuaiream (faidhle, stòr-dàta iomallach)? 

Tha cuimhne air fàs saor, agus bidh dàta sam bith a dh’ fhaodadh a bhith ann airson a’ mhòr-chuid de phròiseactan beaga is meadhanach a’ freagairt air 1 GB de chuimhne. (Mar eisimpleir, is e am pròiseact dachaigh as fheàrr leam rianadair ionmhais, a chumas staitistig làitheil agus eachdraidh mo chosgaisean, cothromachadh, agus gnothaichean airson bliadhna gu leth, ag ithe dìreach 45 MB de chuimhne.)

Pros:

  • Bidh ruigsinneachd air dàta a’ fàs nas fhasa - cha leig thu leas a bhith draghail mu cheistean, luchdachadh leisg, feartan ORM, bidh thu ag obair le nithean àbhaisteach C #;
  • Chan eil duilgheadasan co-cheangailte ri ruigsinneachd bho dhiofar snàithleanan;
  • Gu math luath - gun iarrtas lìonra, gun eadar-theangachadh de chòd gu cànan ceist, gun fheum air (de) sreathachadh de nithean;
  • Tha e iomchaidh dàta a stòradh ann an cruth sam bith - biodh e ann an XML air diosc, no ann an SQL Server, no ann an Azure Table Storage.

Cons:

  • Tha sgèileadh còmhnard air chall, agus mar thoradh air an sin, chan urrainnear cleachdadh ùine downt a dhèanamh;
  • Ma thuiteas an aplacaid, faodaidh tu cuid de dhàta a chall. (Ach cha bhith an tagradh againn a’ tuiteam gu bràth, ceart?)

Ciamar a dh'obraicheas e?

Tha an algorithm mar a leanas:

  • Aig an toiseach, tha ceangal air a stèidheachadh leis an stòradh dàta, agus tha dàta air a luchdachadh;
  • Tha modail nì, prìomh chlàran-amais, agus clàran-amais co-cheangailte (1: 1, 1: mòran) air an togail;
  • Thèid ballrachd a chruthachadh airson atharraichean ann an feartan nì (INotifyPropertyChanged) agus airson eileamaidean a chur ris no a thoirt air falbh (INotifyCollectionChanged);
  • Nuair a thèid an fho-sgrìobhadh a phiobrachadh, thèid an rud atharraichte a chur ris a’ chiudha airson sgrìobhadh chun stòradh dàta;
  • Bidh atharrachaidhean air an stòradh air an sàbhaladh bho àm gu àm (air timer) ann an snàithlean cùil;
  • Nuair a dh’ fhàgas tu an tagradh, thèid atharrachaidhean a shàbhaladh don stòradh cuideachd.

Eisimpleir còd

A 'cur ris na eisimeileachd riatanach

// Основная библиотека
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

Bidh sinn a 'toirt cunntas air a' mhodail dàta a thèid a stòradh anns an stòradh

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; }
}

An uairsin modail an nì:

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;
}

Agus mu dheireadh, an clas stòr fhèin airson faighinn gu dàta:

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();
    }
}

Cruthaich eisimpleir ObjectRepository:

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

Ma chleachdas am pròiseact HangFire

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

A’ cuir a-steach nì ùr:

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

Leis a 'ghairm seo, an nì Modail Phàrant air a chur ris an dà chuid san tasgadan ionadail agus ris a’ chiudha airson sgrìobhadh chun stòr-dàta. Mar sin, bidh an obrachadh seo a’ toirt O(1), agus faodar obrachadh leis an nì seo sa bhad.

Mar eisimpleir, gus an nì seo a lorg anns an ionad-tasgaidh agus dearbhadh gu bheil an nì a chaidh a thilleadh mar an ceudna:

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

Dè thachras? Suidhich () a' tilleadh Faclair Clàr, anns a bheil Faclair Co-rèiteach agus a’ toirt seachad comas-gnìomh a bharrachd de chlàran-amais bun-sgoile agus àrd-sgoile. Leigidh seo leat dòighean a bhith agad airson sgrùdadh le Id (no clàran cleachdaiche neo-riaghailteach eile) gun a bhith ag ath-aithris gu tur thairis air a h-uile nì.

Nuair a bhios tu a’ cur stuthan ris ObjectRepository thèid fo-sgrìobhadh a chur ris gus na feartan aca atharrachadh, agus mar sin bidh atharrachadh sam bith air feartan a’ ciallachadh gun tèid an nì seo a chur ris a’ chiudha sgrìobhaidh. 
Tha ùrachadh thogalaichean bhon taobh a-muigh a’ coimhead an aon rud ri bhith ag obair le nì POCO:

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

Faodaidh tu rud a sguabadh às anns na dòighean a leanas:

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

Bidh seo cuideachd a’ cur an nì ris a’ chiudha sguabaidh às.

Ciamar a tha sàbhaladh ag obair?

ObjectRepository nuair a bhios nithean air an sgrùdadh ag atharrachadh (an dàrna cuid a’ cur ris no a’ sguabadh às, no ag atharrachadh thogalaichean), a’ togail tachartas Modail air atharrachadhfo-sgrìobhadh gu Stòradh. Gnìomhan Stòradh nuair a thachras tachartas Modail air atharrachadh tha atharrachaidhean air an cur ann an 3 ciudha - airson cur ris, airson ùrachadh, agus airson cuir às.

Cuideachd buileachadh Stòradh nuair a thòisicheas iad, cruthaichidh iad timer a dh’ adhbhraicheas atharrachaidhean a shàbhaladh gach 5 diog. 

A bharrachd air an sin, tha API ann gus gairm sàbhalaidh a sparradh: ObjectRepository.Save().

Ro gach sàbhaladh, thèid gnìomhachd gun bhrìgh a thoirt air falbh bho na ciudha an toiseach (mar eisimpleir, tachartasan dùblaichte - nuair a chaidh nì atharrachadh dà uair no nithean a chuir ris / a thoirt air falbh gu sgiobalta), agus dìreach an uairsin an sàbhaladh fhèin. 

Anns a h-uile cùis, tha an rud gnàthach gu lèir air a shàbhaladh, agus mar sin tha e comasach gun tèid nithean a shàbhaladh ann an òrdugh eadar-dhealaichte na chaidh an atharrachadh, a ’toirt a-steach dreachan nas ùire de nithean na bha iad aig an àm a chaidh an cur ris a’ chiudha.

Dè eile a tha ann?

  • Tha na leabharlannan uile stèidhichte air .NET Standard 2.0. Faodar a chleachdadh ann am pròiseact .NET ùr-nodha sam bith.
  • Tha an API sàbhailte snàithlean. Tha cruinneachaidhean a-staigh air an cur an gnìomh stèidhichte air Faclair Co-rèiteach, tha glasan aig luchd-làimhseachaidh tachartais no chan eil feum aca orra. 
    Is e an aon rud as fhiach cuimhneachadh a bhith ga ghairm ObjectRepository.Save();
  • Clàr-amais neo-riaghailteach (feumar àraid):

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

Cò a chleachdas e?

Gu pearsanta, thòisich mi a’ cleachdadh an dòigh-obrach seo anns a h-uile pròiseact cur-seachad oir tha e goireasach agus chan eil feum air cosgaisean mòra airson còmhdach ruigsinneachd dàta a sgrìobhadh no bun-structar trom a chleachdadh. Gu pearsanta, mar as trice bidh stòradh dàta ann an litedb no faidhle gu leòr dhòmhsa. 

Ach san àm a dh’ fhalbh, nuair a thòisich an EscapeTeams tòiseachaidh a tha a-nis marbh (Bha mi a 'smaoineachadh gur e seo a th' ann, airgead - ach chan eil, eòlas a-rithist) - air a chleachdadh airson dàta a stòradh ann an Azure Table Storage.

Planaichean airson an ama ri teachd

Bu mhath leam aon de na prìomh eas-bhuannachdan an dòigh-obrach seo a rèiteachadh - sgèileadh còmhnard. Gus seo a dhèanamh, feumaidh tu an dàrna cuid gnothaichean sgaoilte (sic!), No co-dhùnadh làidir a dhèanamh nach bu chòir an aon dàta bho dhiofar shuidheachaidhean atharrachadh, no leigeil leotha atharrachadh a rèir a’ phrionnsapail “Cò tha ceart mu dheireadh.”

Bho thaobh teignigeach, tha mi a 'faicinn an sgeama a leanas cho comasach:

  • Stòr EventLog agus Snapshot an àite modail nì
  • Lorg suidheachaidhean eile (cuir puingean crìochnachaidh de gach suidheachadh ris na roghainnean? lorg udp? maighstir/tràill?)
  • Dèan ath-riochdachadh eadar eisimpleirean EventLog tro algairim co-aontachd sam bith, leithid RAFT.

Tha duilgheadas eile ann cuideachd a tha a’ cur dragh orm – cuir às do chascade, no lorg chùisean mu bhith cuir às do nithean aig a bheil ceanglaichean bho nithean eile. 

Còd tùs

Ma tha thu air fad gu ruige seo a leughadh, chan eil air fhàgail ach an còd a leughadh; gheibhear e air GitHub:
https://github.com/DiverOfDark/ObjectRepository

Source: www.habr.com

Cuir beachd ann