نظرات مطالب
نحوه اضافه کردن Auto-Complete به جستجوی لوسین در ASP.NET MVC و Web forms
- این هم یک روش دیگر هست. از آن روش‌های ذکر شده در پیشنیازها هم می‌توانید استفاده کنید.
- highlight کردن عبارت جستجو شده در عنوان بازگشت داده شده، توسط افزونه auto-complete انجام می‌شود؛ خودکار است.
نظرات مطالب
رفع مشکل postBack در Master Page و دریافت خطای Operation is not valid due to the current state of the object
چشم، مرسی نکات زیبایی دوستان گفتند، ولی راستش این پروژه برای 2 سال پیش بود، امروز به دلایلی یه گزینه جستجو اضافه کردم و باقی ماجرا ;-)
نظرات مطالب
نحوه اضافه کردن Auto-Complete به جستجوی لوسین در ASP.NET MVC و Web forms
بله. در اینجا مشکلی با ثبت اطلاعات از چندین جدول مختلف، در یک ایندکس وجود ندارد. برای مدیریت جستجوی بهتر روی آن‌ها یک روش این است که در متد MapPostToDocument، فیلد دیگری را به نام مثلا TableName اضافه کنید تا بشود در حین جستجو از آن استفاده کرد.
نظرات مطالب
استفاده از لوسین برای برجسته سازی عبارت جستجو شده در نتایج حاصل
البته من تست نکردم ولی شاید بتوان با توجه به این که میتوان تاریخ را بصورت عدد ذخیره کرد و نیز با استفاده از عبارات با قاعده تمام وظایف جستجو را به لوسین سپرد.
نظرات مطالب
مقایسه‌ای کوتاه بین WCF و ASMX
یک CBT از شرکت APP-DEV در این زمینه هست. باید بگردید پیداش کنید. خیلی خوب است.
این را در گوگل جستجو کنید: CBT Appdev WCF training
نظرسنجی‌ها
آیا برای تولید یک اپلیکیشن نیاز به مشاوره است؟
بله - از فرآیند تولید تا انتشار، آگاهی کاملی ندارم
خیر - جستجو کردن و جمع آوری اطلاعات لازم کفایت می کند
بله - آگاهی از هزینه ها و تجربیات فنی لازم است
خیر - مشاوران در این حوزه اختلاف نظر دارند
مطالب
اصول پایگاه داده - اندیس ها (indices)

با افزایش حجم بانک‌های اطلاعاتی دسترسی سریع به داده‌های مطلوب به یک معضل تبدیل می‌شود. بهمین دلیل نیاز به مکانیزم هایی برای بازیابی سریع داده‌ها احساس می‌شود. یکی از این مکانیزم‌ها اندیس گذاری (indexing) است. اندیس گذاری مکانیزمی است که به ما امکان دسترسی مستقیم (direct access) را به داده‌های بانک اطلاعاتی می‌دهد.

عمل اندیس گذاری  وظیفه طراح بانک اطلاعاتی است که با توجه به دسترسی هایی که در آینده به بانک اطلاعاتی وجود دارد مشخص می‌کند که بر روی چه ستون هایی می‌خواهد اندیس داشته باشد. بعنوان مثال با تعیین کلید اصلی اعلام می‌کند که بیشتر دسترسی‌های آینده من بر اساس این کلید اصلی است و بنابراین بانک اطلاعاتی بر روی کلید اصلی اندیس گذاری را انجام می‌دهد. علاوه بر کلید اصلی می‌توان بر روی هر ستون دیگری از جدول نیز اندیس گذاشت که همانطور که گفته شد این مسئله بستگی به تعداد دسترسی آینده ما از طریق آن ستون‌ها دارد.

پس از اندیس گذاری بر روی یک ستون بسته به نوع اندیس فایلی در پایگاه اطلاعاتی ما ایجاد می‌شود که به آن فایل اندیس (index file) گفته می‌شود. این فایل یک فایل مبتنی بر رکورد (record-based) است که هر رکورد آن محتوی زوج کلید جستجو – اشاره گر می باشد. کلید جستجو را مقدار ستون مورد نظر و اشاره گر را اشاره گری به رکورد مربوط به ان می‌تواند در نظر گرفت.

توجه داشته باشید که اندیس گذاری و مدیریت اندیس ها، همانطور که در این مقاله آموزشی گفته خواهد شد سر بار هایی ( از نظر حافظه و پردازش) را بر سیستم تحمیل می‌نمایند. بعنوان مثال با اندیس گذاری بر روی هر ستونی یک فایل اندیس نیز ایجاد می‌شود بنابراین اگر اندیس‌های ما بسیار زیاد باشد حجم زیادی از بانک اطلاعاتی ما را خواهند گرفت. مدیریت و بروز نگهداری فایل‌های اندیس نیز خود مسئله ایست که سربار پردازشی را بدنبال دارد. بنابراین توصیه می‌شود در هنگام اندیس گذاری حتما بررسی‌ها و تحلیل‌های لازم را انجام دهید و تنها بر روی ستون هایی اندیس بگذرید که در آینده بیشتر دسترسی‌های شما از طریق ان ستون‌ها خواهد بود.

عموما در بانک‌های اطلاعاتی دو نوع اندیس می‌تواند بکار گیری شود که عبارتند  از :

  • اندیس‌های مرتب (ordered indices) : در این نوع کلید‌های جستجو (search-key) بصورت مرتب نگداری می‌شوند.
  • اندیس‌های هش (Hash indices) : در این نوع از اندیس‌ها کلید‌های جستجو در فایل اندیس مرتب نیستند. بلکه توسط یک تابع هش (hash function) توزیع می‌شوند.

در این مقاله قصد داریم به اندیس‌های مرتب بپردازیم و بخشی از مفاهیم مطرح در این باره را پوشش دهیم.

اندیس‌های متراکم ( dense index ):

اولین و ساده‌ترین نوع از اندیس‌های مرتب اندیس‌های متراکم ( dense ) هستند. در این نوع از اندیس‌ها وقتی بر روی ستونی می‌خواهیم عمل اندیس گذاری را انجام دهیم می‌بایست به ازای هر کلید – جست و جو (search-key) غیر تکراری  در ستون مورد نظر، یک رکورد در فایل اندیس مربوط به ان ستون اضافه کنیم. برای روشن شدن بیشتر موضوع به شکل زیر توجه کنید.

شکل 1 – اندیس متراکم (sparse index)

همانطور که در تصوری مشاهده می‌کنید بر روی ستون دوم از این جدول (جدول سمت راست)، اندیس متراکم (dense) گذاشته شده است. بر همین اساس به ازای هر کدام از اسامی خیابان‌ها یک رکورد در فایل اندیس (جدول سمت چپ) آورده شده است. در فایل اندیس می‌بینید که در کنار کلید جستجو یک اشاره گر نیز به جدول اصلی وجود دارد که در هنگام دسترسی مستقیم (direct access) از این اشاره گر استفاده خواهد شد. دقت کنید که کلید‌های جستجو در فایل اندیس بصورت مرتب نگهداری شده اند که نکته ای کلیدی در اندیس‌های مرتب می‌باشد.

مرتب بودن فایل اندیس موجب می‌شود که ما در هنگام جستجوی کلید مورد نظرمان در جدول اندیس بتوانیم از روش‌های جستجویی نظری جست و جوی دو دویی استفاده کنیم و در نتیجه سریع‌تر کلید مورد نظر را پیدا کنیم. این مسئله باعث ببهبود کارایی می‌شود. بعنوان مثال فرض کنید در فایل اندیس یک ملیون رکورد داریم. در این صورت برای یافتن کلید مورد نظرمان در جدول اندیس بروش جست و جوی دو دویی تنها کافی است 20 عمل مقایسه انجام دهیم. بنابراین می‌بینید که مرتب نگهداشتن جدول اندیس چقدر در سرعت بازیابی، تاثیر دارد.

نکته مهمی که در اندیس‌های متراکم باید به آن دقت شود اینست که ما به ازای کلید‌های جستجوی غیر تکراری یک رکورد در جدول اندیس نگهداری می‌کنیم. برای مثال در شکل بالا در ستون مورد نظر ما دو رکورد برای Downtown و سه رکورد برای Perryridge وجود دارد. این در حالی است که در فایل اندیس فقط یک Downtown و Perryridge داریم.

در اندیس‌های متراکم ما امکان دو نوع دسترسی را داریم :

  • دسترسی مستقیم (direct access)
  • دسترسی ترتیبی (sequential access)

دسترسی مستقیم :

توجه داشته باشید که در هنگام کار با یک جدول، فایل‌های اندیس آن به حافظه اصلی آورده می‌شوند (البته ممکن است که بخشی از فایل‌های اندیس به حافظه اصلی نیایند). این در حالی است که فایل اصلی جدول در حافظه جانبی قرار دارد. بنابراین در هنگام بازیابی یک رکورد از برای یافتن محل ان رکورد نیازی به مراجعه زیاد به حافظه جانبی نیست. بلکه در حافظه اصلی بسرعت با یک عمل جستجو  اشاره گر مربوط به رکورد مورد نظر در حافظه جانبی پیدا شده و مستقیما به آدرس همان رکورد می‌رویم و آن را می‌خوانیم. به این دسترسی، دسترسی مستقیم (direct access) می گوییم.

دسترسی ترتیبی :

در برخی از روش‌های اندیس گذاری علاوه بر دسترسی مستقیم امکان دسترسی بصورت ترتیبی نیز وجود دارد. در دسترسی ترتیبی این امکان وجود دارد که از یک رکورد خاص در جدول اصلی بتوانیم رکورد‌های بعد از آن را به ترتیبی منطقی پیمایش کنیم. برای روشن‌تر شدن موضوع به شکل شماره 1 توجه کنید. در انتهای هر رکورد اشاره گری به رکورد منطقی بعدی مشاهده می‌کنید. این اشاره گر‌ها امکان پیمایش و دسترسی ترتیبی را به ما می‌دهند. بعنوان مثال فرض کنید قصد داریم تمامی رکورد‌های حاوی کلید Perryridge را بازیابی نماییم. از آنجایی که در جدول اندیس تنها برای یکی از رکورد‌های حاوی این کلید اندیس داریم، برای بازیابی باقی رکورد‌ها چه باید کرد؟ در چنین شرایطی ابتدا با دسترسی مستقیم اولین رکورد حاوی Perryridge را پیدا کرده و آن را بازیابی می‌کنیم. سپس از طریق اشاره گر انتهای آن رکورد، می‌توان به رکورد بعدی آن دست یافت و به همین ترتیب می‌توان یک به یک به رکورد‌های دیگر دسترسی ترتیبی پیدا نمود.

دقت کنید که رکورد‌های جدول ما بصورت فیزیکی مرتب نیستند. اما اشاره گر‌های انتهای رکورد‌ها طوری مقدار دهی شده اند که بتوان آنها را بصورت مرتب شده پیمایش نمود.

اندیس اولیه  (primary index)  و اندیس ثانویه  (secondary index)  :

بر روی ستون‌های یک جدول می‌توان چندین اندیس را تعریف نمود. اولین اندیسی که بر روی یک ستون از یک جدول گذاشته می‌شود اندیس اولیه (primary index) نامیده می‌شود. عموما این اندیس به کلید اصلی نسبت داده می‌شود، چراکه اولین اندیسی است که بر روی جدول زده می‌شود. توجه داشته باشید که رکورد‌های جدول اصلی بر اساس کلید‌های جستجوی اندیس اولیه بصورت منطقی (با استفاده اشاره گر‌های انتهای رکورد که توضیح داده شد) مرتب هستند. بنابراین امکان دسترسی بصورت ترتیبی وجود دارد. وقتی پس از اندیس اولیه اقدام به اندیس گذاری‌های دیگری می‌کنیم، اندیس‌های ثانویه را ایجاد می‌کنیم که اندکی با اندیس‌های اولیه متفاوت می‌باشند. در اندیس‌های ثانویه دیگر امکان پیمایش و دسترسی ترتیبی وجود ندارد چراکه اشاره گر‌های انتهای رکورد‌ها بر اساس اندیس اصلی (اولیه) مرتب شده اند. بنابراین ما در اندیس‌های ثانویه تنها دسترسی مستقیم خواهیم داشت. شکر زیر نمونه ای از یک اندیس ثانویه را نشان می‌دهد.

شکل 2 – اندیس ثانویه

همانطور که مشاهده می‌کنید علاوه بر اندیس اصلی (بر روی ستون 2) بر روی سومین ستون این جدول اندیس ثانویه متراکم زده شده است. دقت کنید که هر اشاره گر از جدول اندیس به یک باکت (bucket) اشاره دارد. در هر باکت اشاره گر هایی وجود دارد که به رکورد هایی از جدول اصلی اشاره می‌کنند. فلسفه وجود باکت‌ها اینست که در اندیس‌های ثانویه امکان دسترسی ترتیبی وجود ندارد. بنابراین برای مقادیری تکراری در جدول (مثلا عدد 700) نمی‌توان از اشاره گر‌های انتهای رکورد‌ها استفاده نمود. در چنین شرایطی در باکت‌ها اشاره گر مربوط به تمامی رکورد‌های حاوی مقادیر تکراری یک کلید را نگهداری می‌کنیم تا بتوان به انها دسترسی مستقیم داشت. همانطور که مشاهده می‌کنید برای بازیابی رکورد‌های حاوی مقدار 700 ابتدا از جدول اندیس (که مرتب است) باکت مربوطه را پیدا کرده و سپس از طریق اشاره گر‌های موجود در این باکت به رکورد‌های حاوی مقدار 700 دستیابی پیدا می‌کنیم.

اندیس‌های تنک  (sparse index) :

در این نوع از اندیس‌ها بر خلاف اندیس‌های متراکم، تنها به ازای برخی از کلید‌های جستجو در جدول اندیس اشاره گر نگهداری می‌کنیم. بهمین دلیل فایل اندیس ما کوچکتر خواهد بود (نسبت به اندیس متراکم). در مورد اندیس‌های تنک نیز امکان دسترسی ترتیبی وجود دارد. در شکل زیر نمونه از اندیس تنک (sparse) را مشاهده می‌کنید.

شکل 3 – اندیس تنک (sparse index)

همانند شکل 1، در این شکل نیز اندیس اولیه بر روی ستون دوم زده شده است. اما این بار از اندیس تنک استفاده گردیده است. مشاهده می‌کنید که از میان مقادیر مختلف این ستون تنها برای سه کلید  Brighton، Perryridge و Redwood در جدول اندیس رکورد درج شده است. بنابراین برای دست یابی به کلید‌های دیگر باید ابتدا محل تقریبی آن را با جستجو بر روی جدول اندیس پیدا نمود و سپس از طریق پیمایش ترتیبی به رکورد مورد نظر دست یافت. بعنوان مثال برای بازیابی رکورد حاوی مقدار Mianus ابتدا در جدول اندیس کلیدی که از Mianus کوچکتر باشد (یعنی Brighton ) را پیدا می‌کنیم. سپس به رکورد حاولی Brighton می رویم و از آنجا با استفاده از اشاره گر‌های انتهایی رکورد‌ها به سمت رکورد حاوی Mianus حرکت می‌کنیم تا به آن برسیم.

نکته بسیار مهمی که در مورد اندیس‌های تنک مطرح می‌شود اینست که سیستم چگونه باید تشخیص دهد که کدام کلید‌ها را در جدول اندیس نگهداری کند. این تصمیم به مفهوم بلاک‌های حافظه و اندازه انها باز می‌گردد. می‌دانیم که واحد خواندن اطلاعات از حافظه بر اساس بلاک‌ها می‌باشد. این بدان معنی است که در هنگام خواندن رکورد‌های جداول بانک اطلاعاتی، عمل خواندن بصورت بلاکی انجام می‌شود. هنگامی که بر روی یک جدول می‌خواهیم اندیس تنک بزنیم ابتدا باید ببینیم این جدول چند بلاک از حافظه را اشغال کرده است. سپس رکورد‌های اول هر بلاک  را پیدا کرده و به ازای هر بلاک آدرس و کلید جستجوی رکورد اول آن را در جدول اندیس نگهداری کنیم. بدین ترتیب ما به ازای هر بلاک از جدول یک رکورد در فایل اندیس خواهیم داشت و با تخصیص بلاک‌های جدید به ان، طبیعی است که اندیس‌های جدید نیز در فایل اندیس ذخیره خواهند شد.

اندیس‌های چند سطحی  (multi-level index)

در دنیایی واقعی معمولا تعداد رکورد‌های جداول مورد استفاده بسیار بزرگ است و این اندازه دائما در حال زیاد شدن می‌باشد. افزایش اندازه جداول باعث می‌شود که اندازه فایل‌های اندیس نیز رفته رفته زیاد شود. گفتیم برای کارایی هرچه بیشتر باید جدول اندیس مورد استفاده به حافظه اصلی آورده شود تا تعداد دسترسی‌های ما به حافظه جانبی تا حد امکان کاهش یابد. اما اگر اندازه فایل اندیس ما بسیار بزرگ باشد ممکن است حجم زیادی از حافظه اصلی را بگیرد یا اینکه در حافظه اصلی فضای کافی برای ان وجود نداشته باشد. در چنین شرایطی از اندیس‌های چند سطحی استفاده می‌شود. به بیان دیگر بر روی جدول اندیس نیز اندیس زده می‌شود. تعداد سطوح اندیس ما بستگی به اندازه جدول اصلی دارد و هر چه این اندازه بزرگ‌تر شود، ممکن است باعث افزایش تعداد سطوح اندیس شود. در شکل زیر ساختار یک اندیس دو سطحی را مشاهده می‌کنید.

نکته مهم در مورد اندیس‌های چند سطحی اینست که اندیس‌های سطوح خارجی (outer index) از نوع تنک هستند. این مسئله به این دلیل است که اندازه اندیس‌ها کوچک‌تر شود. چراکه اگر اندیس خارجی از نوع متراکم باشد به این معناست که به ازای هر رکورد غیر تکراری باید یک رکورد در فایل اندیس نیز آورده شود و این مسئله باعث بزرگ شدن اندیس می‌شود. بهمین دلیل سطوح خارجی را در اندیس‌های چند سطحی از نوع تنک می‌گیرند. تنها آخرین سطحی که مستقیما به جدول اصلی اشاره می‌کند از نوع متراکم است. به این سطح از اندیس، اندیس داخلی (inner index) گفته می‌شود.

بروز نگهداشتن اندیس‌ها :

با انجام عملیات درج و حذف بروی جداول، جداول اندیس مربوطه نیز باید بروز رسانی شوند. در این بخش قصد داریم به نحوه بروز رسانی جداول اندیس در زمان حذف و درج رکورد بپردازیم.

بروز رسانی در زمان حذف :

اندیس متراکم :

هنگامی که رکوردی از جدول اصلی حذف می‌شود، در صورتی که بر روی ستون‌های آن اندیس‌های متراکم داشته باشیم، پس از حذف رکورد اصلی باید ابتدا کلید جستجوی ستون مربوط را در جدول اندیس پیدا کنیم. در صورتی که از این کلید تنها یک مقدار در جدول اصلی وجود داشته باشد، اندیس آن را از فایل اندیس حذف کرده و اشاره گر‌های انتهای رکورد‌ها را بروز رسانی می‌کنیم. اما اگر از کلید مورد نظر چندین مورد وجود داشته باشد نباید رکورد مورد نظر در جدول اندیس پاک شود. بلکه تنها ممکن است نیاز به ویرایش اشاره گر اندیس باشد. ویرایش در زمانی رخ می‌دهد که اشاره گر جدول اندیس مستقیما به رکوردی اشاره کند که حذف شده باشد، در این صورت باید اشاره گر اندیس را ویراش نمود تا به رکورد بعدی اشاره نماید.

اندیس تنک :

همانند روش قبل ابتدا رکورد اصلی را از جدول حذف می‌کنیم. سپس در فایل اندیس بدنبال کلید جستجوی مربوط به رکورد حذف شده می‌گردیم. در صورتی که کلید مورد نظر در جدول اندیس پیدا شد کلید جستجوی رکورد بعدی در جدول اصلی را جایگزین آن می‌کنیم. چنانچه کلید مربوط به رکورد بعدی در جدول اندیس وجود داشته باشد نیازی به جایگزینی نیست و باید فقط عمل حذف اندیس را انجام داد.

اگر کلید مورد جستجو در جدول اندیس وجود نداشته باشد نیاز به انجام هیچ عملی نیست. در پایان باید اشاره گر‌های انتهای رکورد‌ها را ویرایش نمود تا ترتیب منطقی برای پیمایش ترتیبی حفظ شود.

بروز رسانی در زمان درج:

اندیس متراکم:

در هنگام درج یک رکورد جدید، ابتدا باید کلید موجود در رکورد جدید را در جدول اندیس جستجو نمود. در صورتی که کلید مورد نظر در جدول اندیس یافت نشد، باید رکوردی جدیدی در فایل اندیس درج کرد و اشاره گر آن طوری مقدار دهی نمود تا به رکورد جدید اشاره نماید. اگر کلید مورد نظر  در جدول اندیس وجود داشته باشد دیگر نیازی بروز رسانی اندیس‌ها نیست و تنها کافی است اشاره گرهای انتهای رکورد‌ها بروز رسانی شوند.

اندیس تنک :

در مورد اندیس‌های تنک کمی پیچیدگی وجود دارد. در صورتی که رکورد جدید باعث تخصیص بلاک (block) جدیدی از حافظه به جدول شود، باید به ازای آن بلاک یک اندیس در جدول اندیس‌ها ایجاد شود و آدر آن بلاک را (که در واقع آدرس رکورد جدید نیز می‌شود) در اشاره گرد اندیس قرار داد. اما درغیز این صورت ( در صورتی که رکورد در بلاک‌های موجود ذخیره شود) نیازی به بروز رسانی جدول اندیس‌ها وجود ندارد.

نوع دیگری از اندیس‌های مرتب نیز وجود دارد که اندیس های B-Tree  هستند که در سیستم‌های اطلاعاتی دنیای واقعی بیشتر از آنها استفاده می‌شود. به امید خدا در مطالب بعدی این اندیس‌ها را نیز مورد بررسی قرار خواهیم داد.

موفق و پیروز باشید. 

مطالب
اجرای سرویسهای NodeJS در ASP.NET Core
 این نوشتار در مورد نحوه اجرای سرویس‌های NodeJS در ASP.NET Core می‌باشد؛ زیرا تعداد زیادی از Package‌های سورس باز و با کیفیت بالا به فرم Node package manager یا به اصطلاح NPM موجود و قابل دریافت می‌باشند. NPM بزرگترین مخزن دنیا از لحاظ وجود بسته‌های نرم افزاری سورس باز است. به همین جهت بسته Microsoft.AspNetCore.NodeServices، جهت استفاده از این بسته‌ها در برنامه‌های ASP.NET Core ارائه شده‌است. برای استفاده از سرویسهای Node ابتدا باید ارجاعی را به بسته Microsoft.AspNetCore.NodeServices داشته باشید. برای این منظور میتوانید از دستور dotnet add package Microsoft.AspNetCore.NodeServices استفاده نمایید. البته اگر از آخرین نسخه NET Core. استفاده میکنید، لزومی به ارجاع به بسته فوق نمی‌باشد و به صورت پیشفرض در بسته Microsoft.AspNetCore.All موجود است.
سپس متد ()ConfigurationServices را جهت اضافه کردن میان افزار Node Services به خط لوله درخواستها (request pipeline) ویرایش میکنیم:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddNodeServices();
}

حال میتوانید به وهله‌ای از اینترفیس INodeServices، از طریق تزریق وابستگی‌ها دسترسی داشته باشید. اینترفیس INodeServices یک Api می‌باشد و مشخص می‌کند که کدام قطعه از کد NET. میتواند کد جاوااسکریپتی را که در محیط Node اجرا می‌شود، فراخوانی کند. همچنین میتوانید از خاصیت FromServices برای دریافت وهله‌ای از اینترفیس INodeServices در اکشن خود استفاده نمایید.
public async Task<IActionResult> Add([FromServices] INodeServices nodeServices)
{
    var num1 = 10;
    var num2 = 20;
    var result = await nodeServices.InvokeAsync<int>("AddModule.js", num1, num2);
    ViewData["ResultFromNode"] = $"Result of {num1} + {num2} is {result}";
    return View();
}

سپس کد جاوااسکریپتی متناظر با تابعی را که توسط متد InvokeAsync فراخوانی میشود، به صورت زیر می‌نویسیم:
module.exports = function(callback, num1, num2) { 
  var result = num1 + num2;
  callback(null, result); 
};
دقت کنید که نام فایل جاوااسکریپت باید همنام با پارامتر اول متد InvokeAsync و تعداد پارامترهای تابع باید مساوی با پارامترهایی باشد که به تابع فراخوانی شده جاوااسکریپت ارسال می‌شود.

حال بیاییم مثالی دیگر را مرور کنیم. میخواهیم از صفحه وب درخواستی، عکسی را تهیه کنیم. بدین منظور از کتابخانه url-to-image استفاده میکنیم. برای نصب آن دستور npm install --save url-to-image را در خط فرمان تایپ میکنیم.

بعد از اتمام نصب این بسته، متدی را برای دریافت اطلاعات ارسالی این کتابخانه تدارک میبینیم.

 [HttpPost]
        public async Task<IActionResult> GenerateUrlPreview([FromServices] INodeServices nodeServices)
        {
            var url = Request.Form["Url"].ToString();
            var fileName = System.IO.Path.ChangeExtension(DateTime.UtcNow.Ticks.ToString(), "jpeg");
            var file = await nodeServices.InvokeAsync<string>("UrlPreviewModule.js", url, System.IO.Path.Combine("PreviewImages", fileName));
            return Content($"/Home/Download?img={fileName}");
        }

        public IActionResult Download()
        {
            var image = Request.Query["img"].ToString();
            var fileName = System.IO.Path.Combine("PreviewImages", image);
            var isExists = System.IO.File.Exists(fileName);

            if (isExists)
            {
                Response.Headers.Add($"Content-Disposition", "attachment; filename=\"" + image + "\"");
                var bytes = System.IO.File.ReadAllBytes(fileName);
                return File(bytes, "image/jpeg");
            }
            else
            {
                return NotFound();
            }
        }

سپس متد UrlPreviewModule.js را به صورت زیر مینویسیم:

var urlToImage = require('url-to-image');
module.exports = function (callback, url, imageName) {
    urlToImage(url, imageName).then(function () {
        callback(null, imageName);
    }).catch(function (err) {
        callback(err, imageName);
    });
};


سرویس‌های Node به توسعه دهندگان ASP.NET Core امکان استفاده از اکوسیستم NPM را که دارای قابلیتهای فراوانی می‌باشد، میدهد. 

مطالب
بررسی ORM های مناسب جهت استفاده در اندروید
با آمدن ORM‌ها به دنیای برنامه نویسی، کار برنامه نویسی نسبت به قبل ساده‌تر و راحت‌تر شد. عدم استفاده کوئری‌های دستی، پشتیبانی از چند دیتابیس و از همه مهمتر و اصلی‌ترین هدف این ابزار "تنها درگیری با اشیا و مدل شیء گرایی" کار را پیش از پیش آسان‌تر نمود.
در این بین به راحتی می‌توان چندین نمونه از این ORM‌ها را  نام برد مثل IBatis , Hibernate ,Nhibernate و EF که از معروفترین آن‌ها هستند.
من در حال حاضر قصد شروع یک پروژه اندرویدی را دارم و دوست دارم بجای استفاده‌ی از Sqlitehelper، از یک ORM مناسب بهره ببرم که چند سوال برای من پیش می‌آید. آیا ORM ای برای آن تهیه شده است؟ اگر آری چندتا و کدامیک از آن‌ها بهتر هستند؟ شاید در اولین مورد کتابخانه‌ی Hibernate جاوا را نام ببرید؛ ولی توجه به این نکته ضروری است که ما در مورد پلتفرم موبایل و محدودیت‌های آن صحبت می‌کنیم. یک کتابخانه همانند Hibernate مطمئنا برای یک برنامه اندروید چه از نظر حجم نهایی برنامه و چه از نظر حجم بزرگش در اجرا، مشکل زا خواهد بود و وجود وابستگی‌های متعدد و دارا بودن بسیاری از قابلیت‌هایی که اصلا در بانک‌های اطلاعاتی موبایل قابل اجرا نیست، باعث می‌شود این فریمورک انتخاب خوبی برای یک برنامه اندروید نباشد.

معیارهای انتخاب یک فریم ورک مناسب برای موبایل:
  • سبک بودن: مهمترین مورد سبک بودن آن است؛ چه از لحاظ اجرای برنامه و چه از لحاظ حجم نهایی برنامه
  • سریع بودن: مطمئنا ORM‌های طراحی شده‌ی موجود، از سرعت خیلی بدی برخوردار نخواهند بود؛ اگر سر زبان هم افتاده باشند. ولی باز هم انتخاب سریع بودن یک ORM، مورد علاقه‌ی بسیاری از ماهاست.
  • یادگیری آسان و کانفیگ راحت تر.

OrmLight

این فریمورک مختص اندروید طراحی نشده ولی سبک بودن آن موجب شده‌است که بسیاری از برنامه نویسان از آن در برنامه‌های اندرویدی استفاده کنند. این فریم ورک جهت اتصالات JDBC و Spring و اندروید طراحی شده است.

نحوه معرفی جداول در این فریمورک به صورت زیر است:
@DatabaseTable(tableName = "users")
public class User {
    @DatabaseField(id = true)
    private String username;
    @DatabaseField
    private String password;
 
    public User() {
        // ORMLite needs a no-arg constructor
    }
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
 
    // Implementing getter and setter methods
    public String getUserame() {
        return this.username;
    }
    public void setName(String username) {
        this.username = username;
    }
    public String getPassword() {
        return this.password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}
با استفاده از کلمات کلیدی DatabaseTable@ در بالای کلاس و DatabaseField@ در بالای هر پراپرتی به معرفی جدول و فیلدهای جدول می‌پردازیم.
سورس این فریمورک را می‌توان در گیت هاب یافت و مستندات آن در این آدرس قرار دارند.


SugarORM
این فریمورک مختص اندروید طراحی شده است. یادگیری آن بسیار آسان است و به راحتی به یاد می‌ماند. همچنین جداول مورد نیاز را به طور خودکار خواهد ساخت. روابط یک به یک و یک به چند را پشتیبانی می‌کند و عملیات CURD را با سه متد Save,Delete و Find که البته FindById هم جزء آن است، پیاده سازی می‌کند.

برای استفاده از این فریمورک نیاز است ابتدا متادیتا‌های زیر را به فایل manifest اضافه کنید:
<meta-data android:name="DATABASE" android:value="my_database.db" />
<meta-data android:name="VERSION" android:value="1" />
<meta-data android:name="QUERY_LOG" android:value="true" />
<meta-data android:name="DOMAIN_PACKAGE_NAME" android:value="com.my-domain" />
برای تبدیل یک کلاس به جدول هم از کلاس این فریم ورک ارث بری می‌کنیم:
public class User extends SugarRecord<User> {
    String username;
    String password;
    int age;
    @Ignore
    String bio; //this will be ignored by SugarORM
 
    public User() { }
 
    public User(String username, String password,int age){
        this.username = username;
        this.password = password;
        this.age = age;
    }
}
بر خلاف OrmLight که باید فیلد جدول را معرفی می‌کردید، اینجا تمام پراپرتی‌ها به اسم فیلد شناخته می‌شوند؛ مگر اینکه در بالای آن از عبارت Ignore@ استفاده کنید.

باقی عملیات آن از قبیل اضافه کردن یک رکورد جدید یا حذف رکورد(ها) به صورت زیر است:
User johndoe = new User(getContext(),"john.doe","secret",19);
johndoe.save(); //ذخیره کاربر جدید در دیتابیس


//حذف تمامی کاربرانی که سنشان 19 سال است
List<User> nineteens = User.find(User.class,"age = ?",new int[]{19});
foreach(user in nineteens) {
    user.delete();
}
برای اطلاعات بیشتر به مستندات آن رجوع کنید.


GreenDAO
موقعیکه بحث کارآیی و سرعت پیش می‌آید نام GreenDAO هست که می‌درخشد. طبق گفته‌ی سایت رسمی آن این فریمورک میتواند در ثانیه چند هزار موجودیت را اضافه و به روزرسانی و بارگیری نماید. این لیست حاوی برنامه‌هایی است که از این فریمورک استفاده می‌کنند. جدول زیر مقایسه‌ای است بین این کتابخانه و OrmLight که نشان میدهد 4.5 برابر سریعتر از OrmLight عمل می‌کند.

غیر از این‌ها در زمینه‌ی حجم هم حرف‌هایی برای گفتن دارد. حجم این کتابخانه کمتر از 100 کیلوبایت است که در اندازه‌ی APK اثر چندانی نخواهد داشت.

آموزش راه اندازی  آن در اندروید استادیو، سورس آن در گیت هاب و مستندات رسمی آن.


Active Android
این کتابخانه از دو طریق فایل JAR و به شیوه maven قابل استفاده است که می‌توانید روش استفاده‌ی از آن را در این لینک ببینید و سورس اصلی آن هم در این آدرس قرار دارد. بعد از اینکه کتابخانه را به پروژه اضافه کردید، دو متادیتای زیر را که به ترتیب نام دیتابیس و ورژن آن هستند، به manifest اضافه کنید:
<meta-data android:name="AA_DB_NAME" android:value="my_database.db" />
<meta-data android:name="AA_DB_VERSION" android:value="1" />
بعد از آن  عبارت ;()ActiveAndroid.Initialize را در اکتیویتی‌های مدنظر اعمال کنید:
public class MyActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActiveAndroid.initialize(this);
 
        //ادامه برنامه
    }
}
برای معرفی کلاس‌ها به جدول هم از دو اعلان Table و Column مانند کد زیر به ترتیب برای معرفی جدول و فیلد استفاده می‌کنیم.
@Table(name = "User")
public class User extends Model {
    @Column(name = "username")
    public String username;
 
    @Column(name = "password")
    public String password;
 
    public User() {
        super();
    }
 
    public User(String username,String password) {
        super();
        this.username = username;
        this.password = password;
    }
}
جهت اطلاعات بیشتر در مورد این کتابخانه به مستندات آن رجوع کنید.


ORMDroid
 از آن دست کتابخانه‌هایی است که سادگی و کم حجم بودن شعار آنان است و سعی دارند تا حد ممکن همه چیز را خودکار کرده و کمترین کانفیگ را نیاز داشته باشد. حجم فعلی آن حدود 20 کیلوبایت بوده و نمی‌خواهند از 30 کیلوبایت تجاوز کند.

برای استفاده‌ی از آن ابتدا دو خط زیر را جهت معرفی تنظیمات به manifest اضافه کنید:
<meta-data
  android:name="ormdroid.database.name"
  android:value="your_database_name" />

<meta-data
  android:name="ormdroid.database.visibility"
  android:value="PRIVATE||WORLD_READABLE||WORLD_WRITEABLE" />
برای آغاز کار این کتابخانه، عبارت زیر را در هرجایی که مایل هستید مانند کلاس ارث بری شده از Application یا در ابتدای هر اکتیویتی که مایل هستید بنویسید. طبق مستندات آن صدا زدن چندباره این متد هیچ اشکالی ندارد.
ORMDroidApplication.initialize(someContext);
معرفی مدل جدول بانک اطلاعاتی هم از طریق ارث بری از کلاس Entity می‌باشد .
public class Person extends Entity {
  public int id;
  public String name;
  public String telephone;
}

//====================

Person p = Entity.query(Person.class).where("id=1").execute();
p.telephone = "555-1234";
p.save();

// یا

Person person = Entity.query(Person.class).where(eql("id", id)).execute();
p.telephone = "555-1234";
p.save();
کد بالا دقیقا یادآوری به EF هست ولی حیف که از Linq پشتیبانی نمی‌شود.
سورس آن در گیت هاب

در اینجا سعی کردیم تعدادی از کتابخانه‌های محبوب را معرفی کنیم ولی تعداد آن به همین جا ختم نمی‌شود. ORM‌های دیگری نظیر AndRom و سایر ORM هایی که در این لیست معرفی شده اند وجود دارند.


نکته نهایی اینکه خوب می‌شود دوستانی که از این ORM‌های مختص اندروید استفاده کرده اند؛ نظراتشان را در مورد آن‌ها بیان کنند و مزایا و معایب آن‌ها را بیان کنند.