ولې ټول معلومات په حافظه کې ساتئ؟
د سایټ یا بیکنډ ډیټا ذخیره کولو لپاره ، د ډیری هوښیار خلکو لومړۍ هیله به د SQL ډیټابیس غوره کول وي.
مګر ځینې وختونه فکر ذهن ته راځي چې د ډیټا ماډل د SQL لپاره مناسب ندي: د مثال په توګه ، کله چې د لټون یا ټولنیز ګراف رامینځته کول ، تاسو اړتیا لرئ د شیانو ترمینځ پیچلي اړیکو لټون وکړئ.
ترټولو بد حالت هغه وخت دی چې تاسو په ټیم کې کار کوئ او یو همکار نه پوهیږي چې څنګه د چټک پوښتنو رامینځته کول. تاسو څومره وخت د N+1 ستونزو حل کولو او د اضافي شاخصونو په جوړولو کې مصرف کړی ترڅو په اصلي پاڼه کې انتخاب په مناسب وخت کې بشپړ شي؟
بله مشهوره طریقه NoSQL ده. څو کاله دمخه د دې موضوع په اړه خورا ډیر هیپ شتون درلود - د هر مناسب فرصت لپاره دوی مونګو ډی بی ځای په ځای کړی او د json اسنادو په بڼه د ځوابونو څخه خوښ وو. (په لاره کې، تاسو باید په اسنادو کې د سرکلر لینکونو له امله څومره کرچونه داخل کړئ؟).
زه د بل ، بدیل میتود هڅه کولو وړاندیز کوم - ولې د غوښتنلیک حافظه کې ټول ډیټا ذخیره کولو هڅه مه کوئ ، په وخت سره یې په تصادفي ذخیره (فایل ، ریموټ ډیټابیس) کې خوندي کړئ؟
حافظه ارزانه شوې، او د ډیری کوچنیو او منځنیو پروژو لپاره هر ډول احتمالي ډاټا به د 1 GB حافظې کې فټ شي. (د مثال په توګه، زما د خوښې کور پروژه ده
پرو:
- ډیټا ته لاسرسی اسانه کیږي - تاسو اړتیا نلرئ د پوښتنو ، سست بار کولو ، ORM ځانګړتیاو په اړه اندیښنه ولرئ ، تاسو د عادي C# شیانو سره کار کوئ؛
- د مختلفو تارونو څخه د لاسرسي سره تړلې ستونزې شتون نلري؛
- خورا ګړندی - د شبکې غوښتنې نه ، د پوښتنې ژبې ته د کوډ ژباړه نه ، د شیانو سیریل کولو ته اړتیا نشته؛
- دا د منلو وړ ده چې ډاټا په هر شکل کې ذخیره کړئ - که دا په ډیسک کې XML کې وي، یا په SQL سرور کې، یا د 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 (یا نورو خپلسري کارونکي شاخصونو) لخوا د لټون لپاره میتودونه ولرئ پرته لدې چې په ټولو شیانو کې په بشپړ ډول تکرار شي.
کله چې توکي اضافه کړئ ObjectRepository ګډون د دوی د ملکیتونو بدلولو لپاره اضافه کیږي، نو په ملکیتونو کې هر ډول بدلون د دې لامل کیږي چې دا اعتراض د لیکلو کتار کې اضافه شي.
له بهر څخه د ملکیتونو تازه کول د POCO څیز سره کار کولو ته ورته ښکاري:
myParent.Children.First().Property = "Updated value";
تاسو کولی شئ په لاندې لارو یو شی حذف کړئ:
repository.Remove(myParent);
repository.RemoveRange(otherParents);
repository.Remove<ParentModel>(x => !x.Children.Any());
دا د حذف کولو کتار کې اعتراض هم اضافه کوي.
سپما څنګه کار کوي؟
ObjectRepository کله چې څارل شوي توکي بدل شي (یا اضافه کول یا حذف کول ، یا د ملکیت بدلول) ، پیښه راپورته کوي ماډل بدل شویګډون کړی ISstorage. تطبیقات ISstorage کله چې پیښه رامنځته شي ماډل بدل شوی بدلونونه په 3 کتارونو کې اچول کیږي - د اضافه کولو، تازه کولو او حذف کولو لپاره.
همدارنګه تطبیقونه ISstorage په پیل کولو سره، دوی یو ټایمر رامینځته کوي چې بدلونونه په هر 5 ثانیو کې خوندي کیږي.
سربیره پردې ، د خوندي کولو تلیفون مجبورولو لپاره API شتون لري: ObjectRepository.Save().
د هر خوندي کولو دمخه، بې معنی عملیات لومړی د قطارونو څخه لیرې شوي (د بیلګې په توګه، نقل شوي پیښې - کله چې یو شی دوه ځله بدل شوی یا په چټکۍ سره اضافه شوي / حذف شوي شیان)، او یوازې بیا ځان خوندي کوي.
په ټولو قضیو کې، ټول اوسنی څیز خوندي شوی، نو دا ممکنه ده چې شیان د بدلون په پرتله په بل ترتیب کې خوندي شوي وي، په شمول د شیانو نوې نسخې د هغه وخت په پرتله چې دوی په قطار کې اضافه شوي.
نور څه شته؟
- ټول کتابتونونه د .NET معیاري 2.0 پر بنسټ دي. په هره عصري .NET پروژه کې کارول کیدی شي.
- API تار خوندي دی. د داخلي راټولولو پر بنسټ پلي کیږي متقابل قاموسد پیښې سمبالونکي یا لاکونه لري یا ورته اړتیا نلري.
یوازینی شی چې د یادولو وړ دی تلیفون کول دي ObjectRepository.Save(); - خپلمنځي شاخصونه (ځانګړتیا ته اړتیا لري):
repository.Set<ChildModel>().AddIndex(x => x.Value);
repository.Set<ChildModel>().Find(x => x.Value, "myValue");
څوک یې کاروي؟
په شخصي توګه، ما د دې طریقې کارول په ټولو شوق پروژو کې پیل کړل ځکه چې دا اسانه ده او د معلوماتو لاسرسي پرت لیکلو یا د درنو زیربناوو ځای پرځای کولو لپاره لوی لګښتونو ته اړتیا نلري. په شخصي توګه، په litedb یا فایل کې د معلوماتو ذخیره کول معمولا زما لپاره کافي دي.
مګر په تیرو کې، کله چې اوس ناکاره شوي پیل شوي EscapeTeems (ما فکر کاوه چې دا دلته ده، پیسې - مګر نه، بیا تجربه) - د Azure Table Storage کې د معلوماتو ذخیره کولو لپاره کارول کیږي.
د راتلونکي لپاره پلانونه
زه غواړم د دې تګلارې یو له اصلي زیانونو څخه حل کړم - افقی اندازه کول. د دې کولو لپاره، تاسو یا توزیع شوي لیږد ته اړتیا لرئ (sic!)، یا د قوي ارادې پریکړه وکړئ چې د مختلفو مثالونو څخه ورته ډاټا باید بدلون ونلري، یا اجازه ورکړي چې د اصولو سره سم بدلون ومومي "څوک چې وروستی دی سم دی."
د تخنیکي نظر څخه، زه د امکان تر حده لاندې سکیم ګورم:
- د اعتراض ماډل پرځای د EventLog او سنیپ شاټ ذخیره کړئ
- نور مثالونه ومومئ (په ترتیباتو کې د ټولو مثالونو پای ټکي اضافه کړئ؟ udp کشف؟ ماسټر / غلام؟)
- د هر توافق الګوریتم له لارې د EventLog مثالونو ترمنځ نقل کول، لکه RAFT.
دلته بله ستونزه هم شتون لري چې ما اندیښمن کوي - د cascade حذف کول، یا د شیانو د حذف کولو قضیې کشف کول چې د نورو شیانو سره اړیکې لري.
سرچینه
که تاسو دلته ټولې لارې لوستلې وي، نو ټول هغه څه چې پاتې دي د کوډ لوستل دي؛ دا په GitHub کې موندل کیدی شي:
سرچینه: www.habr.com