<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>پست‌های انتشارات mhkarami97</title>
        <link>https://virgool.io/mhkarami97/feed</link>
        <description>mhkarami97.ir</description>
        <language>fa</language>
        <pubDate>2026-06-16 07:49:42</pubDate>
        <image>
            <url>https://files.virgool.io/upload/publication/xmo89k5s1pii/yn0tjt.png</url>
            <title>mhkarami97</title>
            <link>https://virgool.io/mhkarami97</link>
        </image>

                    <item>
                <title>دیگه برای این کارهای روزانه نیازی به گوگل کردن نداری</title>
                <link>https://virgool.io/mhkarami97/free-telegram-bot-uzwusdxn11yi</link>
                <description>وقتی دنبال یه ابزار ساده می‌گشتم که تاریخ شمسی رو چک کنم یا قیمت طلا رو بدونم، هر بار یا باید اپ نصب می‌کردم یا به سایتی می‌رفتم که نصفش تبلیغ بود. پس تصمیم گرفتم خودم بسازمشون.چند بات تلگرامی که کاملاً رایگان هستن، مستقیم توی تلگرام کار می‌کنن و مهم‌تر از همه — هیچ اطلاعاتی از شما ذخیره نمی‌شه. همچنین بات های جدید هم بهشون اضافه می‌شه.🔤 یادگیری انگلیسی و فارسی@my_english_persian_learner_botمعنی کلمات انگلیسی رو پیدا کن یا معادل فارسی‌شون رو بگیر. ساده‌ترین راه برای تقویت واژگان توی روزمره.📜 شعر فارسی@my_persian_poem_botبرای دوست‌داران ادبیات فارسی. یه بات که شعر می‌ده و حال خوب.📐 تبدیل واحد@my_unit_convert_botتبدیل سریع واحدهای طول، وزن، دما و بیشتر — بدون گوگل کردن.📅 تاریخ شمسی@my_persian_date_botتبدیل تاریخ میلادی به شمسی و برعکس. سریع و بی‌دردسر. به همراه تاریخ شمسی، میلادی، قمری. سنت هم میتونی راحت باهاش بدست بیاری🔡 تغییر فونت@my_font_changer_botمتنت رو با استایل‌های مختلف نمایش بده. مناسب برای بیو اینستاگرام، کپشن یا هر جای دیگه.💰 قیمت‌یاب@what_my_price_botقیمت لحظه‌ای طلا، ارز و... رو مستقیم توی تلگرام چک کن.🌤 آب‌وهوا@what_my_weather_botوضعیت آب‌وهوای شهرت رو سریع ببین.🔒 یه چیزی که برام مهمههیچ‌کدام از این بات‌ها هیچ اطلاعاتی از شما ذخیره نمی‌کنن — نه پیام‌ها، نه موقعیت مکانی، نه هیچ‌چیز دیگه‌ای. حریم خصوصی برام خط قرمزه.📌 از شما می‌خواماگه دوست داری برای یکی از این بات‌ها مطلب آموزشی بذارم، توی کامنت بنویس کدوم — بر اساس درخواست شما می‌نویسم.همچنین اگه بات خاصی نیاز داری که نیستش، پیشنهادت رو بده تا بسازمش. 👇https://t.me/mhkarami_97</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Tue, 02 Jun 2026 16:40:57 +0330</pubDate>
            </item>
                    <item>
                <title>این مطلب من کجاست!!!</title>
                <link>https://virgool.io/mhkarami97/read-write-consistency-vrjlxjnogsbn</link>
                <description>کاربر پست می‌فرسته، صفحه رو Refresh می‌کنه ولی پستش نیست. یه ثانیه بعد ظاهر می‌شه.این باگ نیست. این مشکله Read-Your-Writes Consistencyاین مشکل در کتاب Designing Data-Intensive Applications بصورت خلاصه به این صورت تعریف شده:&quot;After a user writes data, they should see their own write in subsequent reads — regardless of which replica serves the request.&quot;وقتی یه سیستم Leader/Follower Replication داره، Write به Leader می‌ره ولی Read ممکنه از Followerی بیاد که هنوز sync نشده. نتیجه؟ کاربر داده‌ی خودش رو نمی‌بینه.حالا چطور میشه این مورد رو حل کرد؟ ۱. همیشه از Leader بخونیم ساده‌ترین راه‌حل و البته بدترین. این روش Leader رو Bottleneck می‌کنه. Followerها بی‌استفاده می‌مونن. در Multi-Device کار نمی‌کنه.۲. Time Window Routing بعد از Write، برای ۶۰ ثانیه همون کاربر رو به Leader هدایت کن.مشکل: اگر Replication Lag از ۶۰ ثانیه بیشتر شد، چی؟۳. LSN-Based Routing Leader بعد از هر Write، یه Log Sequence Number برمی‌گردونه.Read بعدی فقط به Replicaای می‌ره که LSN اون &gt;= lastWriteLSN باشه.به جای زمان، از موقعیت واقعی Replication استفاده می‌کنه.۴. Commit Token (روش Oracle BDB) 🎯Leader یه Token تولید می‌کنه، Client اون رو نگه می‌داره و با هر Read ارسال می‌کنه. Replica چک می‌کنه که آیا به اون Transaction رسیده یا نه.در پروژه‌های ترکیب Redis + LSN-Based Routing بهترین تعادل بین دقت و scalability رو می‌ده.حالا به چه صورت؟ بعد از هر Write، commitPosition رو با TTL در Redis ذخیره کنیم. در Read، فقط Replicaای رو انتخاب کنیم که به اون position رسیده.اگه این مشکل رو داری نادیده می‌گیری، کاربرهات دارن این تجربه رو می‌کنن — و فکر می‌کنن bug. پس اگه سیستمی با تعداد یوزر زیاد و هم زمانی زیاد داری بهتره که حواست به این مورد باشه.نمونه کد حل این مشکل
blog.mhkarami97.ir/posts/read_write_consistency
</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Mon, 01 Jun 2026 13:41:14 +0330</pubDate>
            </item>
                    <item>
                <title>راهنمای خرید کتاب‌خوان با توجه به استفاده شخصی</title>
                <link>https://virgool.io/mhkarami97/buy-book-readeer-qncgdpgcnewf</link>
                <description>با توجه به اینکه تقریبا کتاب زیاد می‌خوانم و چند سالی است که نسخه الکترونیکی کتاب‌ها را به دلیل امکاناتی مانند یادداشت برداری راحت‌تر استفاده می‌کنم، تصمیم گرفتم تا یک کتاب‌خوان برای مطالعه راحت‌تر و همچنین آسیب نرسیدن به چشم خریداری کنم. که در این مطلب تجریبات چند ماهه خودم را از این وسیله برای شما نوشتم تا اگر قصد خرید داشتید راحت‌تر بتوانید کتاب‌خوان خود را بخرید.قبل از شروع کتاب‌هایی را که می‌خوانم در لینک زیر خلاصه‌ای از آنها یادداشت می‌کنم:book.mhkarami97.irنکته قوت کتاب‌خوان‌ها نداشتن نور صفحه است و برای مطالعه در آن شبیه به کتاب‌های چاپی نیاز به نور محیط است و در واقع متن کتاب در آن توسط جوهر الکترونیک درست می‌شود. پس صفحه آن کاملا با موبایل یا تب‌لت فرق دارد و هیچ کدام از آنها جای همدیگر را نمی‌گیرند.کتاب‌خوانی که من خریدم، Boox Poke 3 بود که برای خرید آن هم از سایت زیر اقدام کردم:کتابخوان Boox Poke 3 E-ink-ارسال 7 الی 10 روز کاری – میکرولس | Microlessدیجیکالا هم کالای گفته شده را موجود دارد اما در زمان خرید قیمت آن با سایت گفته شده 2 میلیون فرق داشت. این سایت کالاها را مستقیم از دبی وارد می‌کند و با پست برای شما ارسال می‌کند. همچنین قاب برای کتاب‌خوان گفته شده در اینترنت موجود نیست اما این سایت قاب هم برای کتاب‌خوان گفته شده را بصورت رایگان برای من ارسال کرد و می‌توان گفت تجربه اولین خرید خوبی از سایت گفته شده دارم.کتاب‌خوان های مختلفی در اینترنت وجود دارد و یکی از شرکت‌های معروف که آن را تولید می‌کند هم Amazon است. اما محصولات آن خیلی در ایران کاربرد ندارد، زیرا امکان نصب نرم افزار را ندارد و حتما باید از اپ مخصوص خود آمازون استفاده کنید و یا فایل pdf کتاب را داخل آن بریزید. اصولا خواندن کتاب با فرمت pdf حتی در کتاب‌خوان سخت است و فرمت epub که در اپ های خرید کتاب مانند فیدیبو و طاقچه از آن استفاده می‌شود بسیار کاربردی تر است که امکان تغییر فونت و اندازه نوشته را دارد.پس برای نکته اول پیشنهاد می‌کنم کتاب‌خوانی بگیرید که دارای سیستم عامل اندروید باشد تا بتوانید اپ‌‎های کتاب‌خوان فارسی را در آن نصب کنید. این کتاب‌خوان دارای اندروید 10 است و شبیه به موبایل می‌توانید بر روی آن اپلیکیشن نصب کنید.حافظه داخلی و پشتیبانی از رم هم مهم است تا بتوانید بدون مشکل تعداد زیادی کتاب بر روی دستگاه داشته باشید، این کتاب‌خوان حافظه داخلی 32 گیگ دارد اما از رم پشتیبانی نمی‌کند. البته تا کنون از این مقدار حافظه با مشکلی مواجه نشده‌ام.داشتن کاور هم تا حدودی مهم است تا راحت بتوانید آن را حمل کنید و نگران خش افتادن روی آن نباشید.سبک بودن هم نکته دیگری است که باید به آن توجه کنید، با توجه به اینکه آن را شبیه کتاب نگه می‌دارید پس باید سبک باشد تا دست خسته نشود.نگه داشتن شارژ هم مهم است، کتاب‌خوان گفته شده تقریبا 2 هفته در حالت مطالعه روزانه شارژ نگه می‌دارد.این کتاب‌خوان تقریبا از کف دست باز شده کمی بزرگتر است، اگر می‌خواستید می‌توانید سایزهای بزرگ‌تر هم بخرید اما به این نکته توجه کنید که با بزرگ شدن حمل آن سخت‌تر می‌شود و هم وزن آن بیشتر می‌شود.بیشتر موارد دیگر را تمام کتاب‌خوان‌ها دارند، مانند اتصال به اینترنت و بلوتوث، پشتیبانی از نور گرم برای مطالعه در تاریکی، امکان وارد کردن فایل با سیم و ... که تفاوت خاصی بین مدل‌های مختلف نیست.لینک انجمن:[اختصاصی] تجربه من از کتاب‌خوان یا Book Reader - راهنمایی خرید - انجمن آی ترفند (itarfand.com)</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Sun, 15 Jan 2023 12:46:19 +0330</pubDate>
            </item>
                    <item>
                <title>تجربه من از تعمیر کوادکوپتر</title>
                <link>https://virgool.io/mhkarami97/fix-kovad-kopter-c0iik9y6nrfi</link>
                <description>یکی از وسایلی که جدیدا خریده بودم اما متاسفانه زمان اولیل استفاده خراب بود، کوادکوپر یا همان پهپاد بود. ظاهرا در همان اولین پرواز یکی از پره‌های وسیله به جایی گیر کرده بود و باعث خراب شدن و نچرخیدن آن شده بود.پهپاد گفته شده را از فروشگاه اینترنتی خریده بودم، یکی از نکات عجیب این فروشگاه تعداد زیاد امتیازهای مثبت سایت در گوگل بود که بعد از خرید دلیل آن را متوجه شدم، در صورت ثبت امتیاز توسط افراد آنها در خریدهای بعدی از سایت تخفیف دریافت می‌کردند. البته دلیل گفته شده به معنی بد بودن فروشگاه نیست و من فقط تجربه خودم را در این مطلب بیان کرده‌ام.به علت نداشتن تجربه قبلی در تعمیر کوادکوپتر با فروشگاه تماس گرفتم و وسیله را برای آنها ارسال کردم که بعد از تاخیر چند روزه در بررسی کالا و تماس دوباره با فروشگاه گفتند که وسیله پرواز کرده است و امکان عوض کردن آن وجود ندارد اما می‌توانند آن را با هزینه 900 هزار تومان تعمیر کنند.قسمت جالب ماجرا از این نقطه شروع می‌شود که من تصمیم گرفتم این هزینه را نکنم و خودم پهپاد را تعمیر کنم. پس وسیله را از آنها پست گرفتم و بعد شروع به جستجو در اینترنت درباره پهپاد و قطعات آن کردم.ساختار داخلی اسباب بازی‌ها خیلی شبیه هم هست، بیشترشون آرمیچر دارند که با چرخ دنده قسمت دیگری را می‌چرخوانند. پس شروع به باز کردن وسیله کردم.ابتدا فقط یکی از پره‌ها که نمیچرخید را باز کردم تا دلیل نچرخیدن آن را پیدا کنم، برای من پره پایین، چپ نمی‌چرخید. موتورها و پره‌های پهپاد با توجه به جایی که هستند نوع مختلفی دارند تا در جهت مخالف هم بچرخند تا تعادل پهپاد در هوا حفظ شود. بطور مثال پره گفته شده B بود و سیم‌های آبی/قرمز بود. در حالیکه پره بالایی نوع A و سیم‌های سیاه/سفید داشت. پس اگر نیاز به خرید موتور داشتید به این نکته دقت کنید.اولین موردی که دیدم عدم اتصال چرخ دنده عکس زیر بود که هرکدام آزادانه می‌چرخید اما بطور مثال در پره بالایی این دو به هم متصل بودند. پس شروع به جستجو در اینترنت برای خرید این چرخ دنده کوچک تقریبا زرد رنگ کردم.با جستجو متوجه شدم که چرخ دنده گفته شده دارای تعداد پره‌های مختلف و همچنین قطرهای مختلف است. پس مشخصات گفته شده را بدست آوردم. برای پهپاد من این قطعه 12 پره و قطر کلی 3.8 و قطر داخلی 1 که میله داخل آن می‌شود بود. پس از سایت زیر چند عدد از چرخ دنده گفته شده را خریدم:چرخ دنده 12T کوادکوپتر هلیشات چرخدنده 12 گام (electrastore.ir)اگر شما نیاز به خرید موتور داشتید هم شبیه مورد بالا می‌توانید مشخصات موتور خود را بدست آورید و از اینترنت آن را خریداری کنید:موتور هلیکوپتر , کوادکوپتر ,موتور پهباد,ارمیچر کواد,آرمیچر کواد (electrastore.ir)بعد از تحویل قطعه گفته شده متوجه شدم که قطر داخلی آن کمتر از چرخ دنده موجود است و وارد میله موتور نمی‌شود. پس با سوزن و کبریت برای داغ کردن سوزن و چند بار تلاش قطر آن را بیشتر کردم تا داخل میله بشود.متاسفانه بعد از وارد کردن آن باز متوجه شدم که چرخ دنده‌ها به هم تماس ندارند و هرکدام جدا می‌چرخند. پس شروع به مقایسه 2 پره مختلف پهپاد کردم. ابتدا جای موتور را کامل تغییر دادم و موتور B را در A قرار دادم تا ببینم مشکل را از اول درست متوجه شده بودم یا نه. در کمال تعجب موتوری که چرخ دنده آن را تغییر داده بودم آنجا درست کار کرد ولی موتور سالم A در بخش پایین درست کار نمی‌کرد.پس متوجه شدم که از اول قطعه اشتباهی را دلیل مشکل می‌دانستم. پس دوباره شروع به بررسی پره درست خراب کردم. با کمی دقت متوجه شدم که ظاهرا پلاستیک کمی کج شدن است و باعث می‌شود فاصله دو چرخ دنده از هم زیاد بشود. در دو عکس زیر اولی برای قطعه درست است که موتور و میله چرخواننده سمت راست آن موازی هستند و دومی برای قسمت خراب است که کمی کج است.از اینترنت شماره محلی که تعمیرات اسباب بازی و کوادکوپتر را انجام می‌داد بدست آوردم تا از او در این رابطه کمی کمک بگیرم.بعد از رفتن به محل گفته شده، قسمت پلاستیکی که کج شده بود را نداشت اما راه حل بسیار ساده‌ای برای تعمیر گفت. طبق گفته او گرما باعث شده است پلاستیک کج شود و دو چرخ دنده به هم نرسند، پس با سشوار و گرم کردن پلاستیک بزرگ نقره‌ای رنگ و کمی کج کردن محلی که موتور وارد آن می‌شود می‌توان این مشکل را حل کرد.پس به خانه برگشتم و شروع به تلاش دوباره کردم. قطعه را جلو سشوار نگه می‌داشتم و بعد با دست سعی می‌کردم پلاستیک قسمتی که موتور وارد آن می‌شد را به سمت راست بکشم تا موازی قسمت دیگر شود. چند بار این کار را تکرار کردم و بعد برای تست موتور و چرخ دنده را وارد آن کردم. فاصله چرخ دنده‌ها کم شده بود و با هم تماس داشتند اما هنوز کمی فاصله وجود داشت.راحت‌ترین راهی که  به ذهنم رسید استفاده از چوب کبریت بود، پس آن را با چاقو کم برش دادم و نازک کردم و کنار موتور وارد کردم تا چرخ دنده آن نزدیکتر به چرخ دنده بزرگ بشود. خوشبختانه در این مرحله دو چرخ دنده به هم رسیدند.پس با کمی تلاش، یک چوب کبریت و خرید چند چرخ دنده توانستم خودم کوادکوپتر را تعمیر کنم و نیازی به پرداخت هزینه اضافی نداشته باشم و همچنین با قطعات آن برای تعمیرهای آینده آشنا شود.لینک انجمن:[اختصاصی] آموزش تعمیر کوادکوپتر - مشکلات سخت افزاری - انجمن آی ترفند (itarfand.com)</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Sun, 15 Jan 2023 12:17:09 +0330</pubDate>
            </item>
                    <item>
                <title>مشاهده YouTube بدون استفاده از نرم افزار واسط</title>
                <link>https://virgool.io/mhkarami97/alternative-youtube-c4pv7pcmthdd</link>
                <description>اگر حریم خصوصی برای شما مهم است و دوست دارید شبکه‌های اجتماعی سایت‌هایی که مشاهده می‌کنید را ردیابی کنند، این افزونه کار شما را بسیار راحت می‌کند. همچنین توسط این ابزار می‌توانید سایت YouTube را بدون نرم‌افزار واسط دیگری مشاهده کنید.ابتدا از لینک زیر افزونه مورد نظر را دانلود کنید و سپس مرورگر خود را باز کنید و به بخش Extensions بروید. در این بخش گزینه Development را فعال کنید و سپس توسط Load unpacked فایل دانلود شده (ابتدا از حالت فشرده آن را خارج کنید) را انتخاب کنید.افزونه مورد نظر اکنون نصب شده است.اگر در نصب مشکلی داشتید فیلم آموزشی در لینک زیر هم موجود است.chromiumبرای مشاهده سایت یوتیوب به بخش Setting افزونه بروید و از سمت چپ YouTube را انتخاب کنید.اکنون گزینه Fronted را بر روی Piped قرار دهید و از بخش پایین تیک گزینه https://piped.mha.fi را بزنید.اکنون اگر در نتایج جستجو گوگل بر روی فیلمی کلیک کنید بصورت اتومات فیلم مورد نظر باز بدون نیاز به نرم‌افزار واسط دیگری باز می‌شود.libredirectلینک وبلاگ:مشاهده YouTube بدون ابزار خاص - روزمرگی های یک برنامه نویس (mhkarami97.ir)</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Sun, 08 Jan 2023 09:03:09 +0330</pubDate>
            </item>
                    <item>
                <title>اجرا کردن بخشی از کد خارج از Transaction</title>
                <link>https://virgool.io/mhkarami97/transaction-scope-suppress-xlz9phfqbg7n</link>
                <description>فرض کنید در یک تراکنش بانکی نیاز دارید که در صورت به خطا خوردن بخشی از کد، تمام موارد انجام شده هم به حالت قبل برگردند. بطور مثال اگر انتقال پول به خطا خورد موجودی کاربر اولیه دوباره افزایش یابد. در این موارد می‌توانید از Transaction استفاده کنید.حال فرض کنید در داخل این عملیات نیاز دارید تا بخشی را خارج از ترنزکشن انجام دهید تا حتی اگر کد به خطا خورد هم انجام شود. در این موارد کافی است یک Transaction جدید باز کنید و حالت آن را Suppress قرار دهید:using (var scope = new TransactionScope(TransactionScopeOption.Required, option, TransactionScopeAsyncFlowOption.Enabled))
{

// Some code

 using (var tx = new TransactionScope(TransactionScopeOption.Suppress))
{
    InsertMoneyAction(ActionState.Active);
    tx.Complete();
}

// Some Code

scope.Complete();
}مورد مهم در کد بالا تفاوت TransactionScopeOption و TransactionScopeAsyncFlowOption است. هر دو مقدار Suppress را دارند اما مورد مورد نیاز ما TransactionScopeOption.Suppress است که عمل انجام شده را انجام می‌دهد. در واقع دو کد زیر کاملا متفاوت هستند و یک کار را انجام نمی‌دهند:using (var tx = new TransactionScope(TransactionScopeOption.Suppress))
{
    InsertMoneyAction(ActionState.Active);
    tx.Complete();
}using (var tx = new TransactionScope(TransactionScopeAsyncFlowOption.Suppress))
{
    InsertMoneyAction(ActionState.Active);
    tx.Complete();
}transactionscopeasyncflowoptiontransactionscopeoptionلینک وبلاگ : اجرا کردن بخشی از کد خارج از Transaction - روزمرگی های یک برنامه نویس (mhkarami97.ir)</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Wed, 02 Nov 2022 10:26:59 +0330</pubDate>
            </item>
                    <item>
                <title>Collation حساس به حروف بزرگ و کوچک در SQL Server</title>
                <link>https://virgool.io/mhkarami97/collation-on-sql-server-nnbzpvnkaf6z</link>
                <description>در یکی از پروژه‌ها نیاز به انتقال تمام اطلاعات جداول به دیتابیس جدید بود که در انجام این کار که در مطلب قبلی کلیات آن گفته شد به چند خطا هم برخورد کردیم.خطا زیر را ابتدا مشاهده کردیم:Cannot insert duplicate key row in object ‘dbo.Response’ with unique index ‘FUIX_Dbo_Response(MessageId)’. The duplicate key value is (331BAv80AAAAAAAA).بعد از بررسی‌های بیشتر به این موارد رسیدیم:دیتابیس جدید توسط Generate Script از دیتابیس قدیم ساخته شده بود و نکته‌ای که وجود داشت این بود که این ابزار SQL Server Management Script مشکلی دارد که Collation جداول را منتقل نمی‌کند.خطا بالا هم دقیقا به همین دلیل بود. در دیتابیس قدیمی Collation مقدار PERSIAN_CS_AI داشت که حساس به حروف کوچک و بزرگ بود. پس مقدار 331BAv80AAAAAAAA با 331BAV80AAAAAAAA تفاوت می‌کرد اما در دیتابیس دوم این مورد رعایت نشده بود که باعث خطا بالا می‌شد.همچنین ابزار گفته شده Collation خود دیتابیس هم منتقل نمی‌کند که باعث شده بود برای دیتابیس جدید مقدار SQL_Latin1_General_CP1_CI_AS بگیرد که باعث خراب شدن دیتا و نیاز به انتقال دوباره تمام اطلاعات بود.همچنین بعد از انتقال اطلاعات امکان تغییر Collation دیتابیس بسیار سخت است و لازم است تمام Constraint های دیتابیس پاک شود که حتی بعد از این کار اطلاعاتی که قبلا منتقل شده بودند هم درست نمی‌شود و بطور مثال حروف فارسی را علامت سوال نشان می‌دهد.collationscollations case sensitivityلینک وبلاگ:Collation حساس به حروف بزرگ و کوچک در SQL Server - روزمرگی های یک برنامه نویس (mhkarami97.ir) https://virgool.io/p/nnbzpvnkaf6z/edit  https://virgool.io/p/nnbzpvnkaf6z/edit </description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Tue, 18 Oct 2022 10:43:47 +0330</pubDate>
            </item>
                    <item>
                <title>منتقل کردن دیتا به دیتابیس جدید در SQL Server</title>
                <link>https://virgool.io/mhkarami97/transferdatasqlserver-adnrqtfjf0cs</link>
                <description>در یکی از پروژه‌های شرکت نیاز به انتقال تمام دیتا دیتابیس به یک دیتابیس جدید بود. برای انجام این کار بعد از بررسی کوئری‌های مختلف به کوئری زیر رسیدیم. از راه‌های دیگر انتقال می‌توان به جوین زدن بین دو جدول برای جلوگیری از انتقال دیتا تکراری اشاره کرد که البته اینکار سنگین‌تر از این کوئری بود. کوئری زیر در واقع دیتا تکراری را بررسی نمی‌کند و تمام دیتا را منتقل می‌کند. ممکن است این کوئری به خطا بخورد و بخشی از دیتا منتقل نشود که برای حل این مشکل از کوئری دوم استفاده می‌شود و برای کارکرد درست آن هم Id جدول هم منتقل می‌شود تا در انتها بتوان صحت دیتا و همچنین انتقال دیتاهای جا مانده را انجام داد:SET IDENTITY_INSERT [DB2].[dbo].[Request] ONیکی از موارد مهم در کوئری که در واقع از ویژگی‌های خود SQL می‌شود، ادامه دادن کوئری در مواقع به خطا خوردن است. بطور مثال در کوئری زیر خط 3 و 4 هم اجرا می‌شوند:SELECT 1
SELECT 2
SELECT 5/0
SELECT 3
SELECT 4پس در این کوئری حتی اگر یک Batch هم به خطا بخورد بقیه دیتا منتقل می‌شود و فقط دیتا همان Batch جا می‌ماند.همچنین دقت کنید که اگر یک Batch را یک عدد بطور مثال یک میلیون قرار دهید، به معنی انتقال یک میلیون سطر نیست. زیرا ممکن است در خود Id ها گپ وجود داشته باشد که از دلایل آن می‌توان به پاک شدن دیتا اشاره کرد.قرار دادن Batch Size هم به دلیل جلوگیری از پر شدن Log دیتابیس است. در غیر این صورت به دلیل پر شدن تمام ترافیک شبکه و فایل لاگ دیتابیس به حالت Recovery می‌رود و هیچ کوئری دیگر را هم نمی‌توانید بر روی آن اجرا کنید. اندازه هر batch را هم با توجه به جدول اصلی، منابع سرور و .. می‌توانید تعیین کنید. بطور مثال اگر جدول اصلی 500 میلیون سطر داشته باشد می‌توانید از اندازه 5 میلیون و اگر 1 میلیارد سطر داشته باشد از مقدار 100 میلیون استفاده کنید.مقدار WITH (NOLOCK) هم برای این است که دیتابیس اولیه قفل نشود تا بقیه افراد بصورت عادی بتوانند از آن استفاده کنند.اجرا کردن این کوئری در زمان‌های متفاوت هم ممکن است سرعت‌های متفاوتی داشته باشد. بطور مثال اگر افراد دیگری هم در حال اجرا کوئری بر روی دیتابیس اولیه باشند با توجه به مشغول شدن بخشی از منابع سرور اولیه با کندی مواجه می‌شوید.DECLARE @batchSize BIGINT;
DECLARE @MinId BIGINT;
DECLARE @MaxId BIGINT;
SET @batchSize = 1000000;

SELECT @MinId = MIN(Id),
       @MaxId = MAX(Id)
FROM [DB1].[dbo].[Request]

SET IDENTITY_INSERT [DB2].[dbo].[Request] ON

WHILE (@MinId &lt;= @MaxId)
    BEGIN
        INSERT INTO [DB2].[dbo].[Request]
        ( [Id]
        , [DecisionId]
        , [ErrorCode]
        , [Description]
        , [CreationDate])
        SELECT I.[Id]
             , I.[DecisionId]
             , I.[ErrorCode]
             , I.[Description]
             , I.[CreationDate]
        FROM [DB1].[dbo].[Request] I WITH (NOLOCK)
        WHERE I.Id &gt;= @MinId
          AND I.Id &lt; @MinId + @batchSize

        SET @MinId = @MinId + @batchSize
    END

SET IDENTITY_INSERT [DB2].[dbo].[Request] OFFممکن است کوئری بالا به دلایل مختلف به خطا بخورد. بطور مثال شبکه قطع شود، دیتا اشتباه باشد و … در این مواقع می‌توانید با کوئری زیر دیتایی که منتقل نشده است را منتقل کنید.یکی از خطاهای کوئری بالا خطا زیر ممکن است باشد:A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 0 - The semaphore timeout period has expired.)این خطا در مواقعی پیش می‌آید که Session شما قطع می‌شود که از دلایل آن می‌توان به Policy های تیم امنیت شرکت برای جلوگیری از اجرا کوئری‌ها در ساعات خاصی از روز باشد.DECLARE @CurrentId BIGINT = 1;
DECLARE @BatchSize INT = 1000000;
DECLARE @MaxId BIGINT = (SELECT MAX(Id)
                         FROM [DB1].[dbo].[Request]);

WHILE (@CurrentId &lt; @MaxId)
    BEGIN
        INSERT INTO [DB2].[dbo].[Request](Id, DecisionId, ErrorCode, Description, CreationDate)
        SELECT I1.Id, I1.DecisionId, I1.ErrorCode, I1.Description, I1.CreationDate
        FROM [DB1].[dbo].[Request] I1
                 LEFT JOIN
             [DB2].[dbo].[Request] I2 ON I1.Id = I2.Id
        WHERE I2.Id IS NULL
          AND I1.Id BETWEEN (@CurrentId + 1) AND (@CurrentId + @BatchSize)

        SET @CurrentId += @BatchSize;
    ENDبرای مطمئن شدن از انتقال کامل دیتا هم می‌توانید از کوئری زیر استفاده کنید. استفاده از COUNT راحت‌ترین راه است که البته اگر دیتا زیاد باشد کمی زمانبر می‌شود.خط آخر که در واقع یک SP است بسیار سریع تعداد سطرهای جدول را نشان می‌دهد.SELECT COUNT(*) FROM [DB1].[dbo].[Request] WITH (NOLOCK)
SELECT COUNT(*) FROM [DB2].[dbo].[Request] WITH (NOLOCK)

EXEC sys.sp_spaceused @objname = N&#039;[dbo].[Request]&#039;لینک به وبلاگ:منتقل کردن دیتا به دیتابیس جدید در SQL Server - روزمرگی های یک برنامه نویس (mhkarami97.ir) https://virgool.io/p/adnrqtfjf0cs/edit </description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Tue, 18 Oct 2022 10:39:50 +0330</pubDate>
            </item>
                    <item>
                <title>موجیم، که آرامش ما عدم ماست (مهاجرت به لینوکس)(03)(شروع کد نویسی)</title>
                <link>https://virgool.io/mhkarami97/install-net-core-and-sql-server-in-linux-pd1pintbpnyg</link>
                <description>اگه قسمت های قبل رو دنبال کرده باشید، میدونید که چندتا مشکل ساده رو حل کردیم و تونستیم سیستم رو بالا بیاریمموجیم، که آرامش ما عدم ماست (مهاجرت به لینوکس)(02)(پکیج منجر) - itarfand (virgool.io)همه چی خوب پیش میرفت و من از همین تعجب میکردم، اما انگار سکوت قبل از طوفان بودش!!!من میخواستم با .net core برنامه بنویسم و از دیتابیس sql server استفاده کنم، پس شروع کردم به نصب .net coreطبق لینک خود مستنداتش میرفتم جلو:https://docs.microsoft.com/en-us/dotnet/core/install/linuxتو لینک بالا از همون پکیج منجر snap هم گفته میشه نصب کرد، پس من هم دستوری که گفته بود رو زدم و با موفقیت نصب شد.برای برنامه نویسی هم چند ماهی هستش که از Jetbrains Rirder استفاده میکنم و واقعا هم ازش راضی هست. نکته خوبش اینه که توی لینوکس هم میشه نصبش کردیکی از پروژ هایی که داشتم رو با Rider بازش کردم که اینجا اولین مشکل بوجود اومد. dependencies های پروژه نصب نمیشدن و ظاهرا Nuget نمیتونست پکیج ها رو دریافت کنهیه مقدار جستجو کردم (البته این یه مقدار اسمش هست و بیشتر کار برد!!) که به نتیجه ای نرسیدم، گفتم بزار ببینم میشه Nuget رو جدا نصب کرد که دیدم بله !!!پس طبق مطلب زیر شروع به نصبش کردم:https://stackoverflow.com/a/40209368/10233323مشکل اول حل شد و پکیج ها نصب شدن و پروژه هم با موفقیت بیلد شدغول بعدی که منتظرم بود SQl Server هستشداکیومنت این قسمت در لینک زیر دردسترس هستش:https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-setup?view=sql-server-ver15با دستورهای زیر میتونید sql رو توی لینوکس نصب کنید:sudo apt-get update
sudo apt-get install mssql-serverبعد باید خطهای زیر رو طبق عکس به فایل .bashrc اضافه کنیدتو عکس بالا از قسمت export تا انتها رو باید اضاف کرد. البته بعضی قسمتهاش برای .net core هست و از اول تا mssql-tools/bin برای sql server هستexport PATH=&amp;quot$PATH:/opt/mssql-tools/binیکی از مشکلاتی که بعد از اضافه کردن این قسمت داشتم، خطا دادن terminal بود. یه چند ساعتی وقت گرفت تا بدونم مشکل چیه. اشتباها کلمه export رو به esac چسبونده بودمبعد از جستجو متوجه شدم که برای فایل .bashrc یه فایل دیفالت هم توی پوشه rtc هستش. بعد از نگاه کردن به این فایل متوجه اشتباهم شدم ?بعد از انجام کار بالا توی ترمینال باید دستور زیر رو وارد کنید تا کافنیگ sql server شروع بشهsudo /opt/mssql/bin/mssql-conf setupبا انجام کار بالا قسمت زیر میاد که من گزینه 2 که نسخه رایگان sql server هست رو انتخاب کردمبعد از انجام کارهای بالا باید دستور sqlcmd توی ترمینال شناخته بشه، پس دستور زیر رو وارد کنید:sqlcmd -S localhost -U SA -Q &#039;select @@VERSION&#039;خب یکی دیگه از مشکلات رو حل کردم و میخواستم برنامه رو Start کنم که مشکلات بعدی بوجود اومدتو قسمت بعدی به ادامه شاخ غول شکستن میپردازیم ?</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Wed, 07 Apr 2021 14:28:06 +0430</pubDate>
            </item>
                    <item>
                <title>استفاده از unique index در ستون با مقدار null توسط Filter Index</title>
                <link>https://virgool.io/mhkarami97/unique-index-in-nullable-column-y6dpaugsjyep</link>
                <description>در تغییری که لازم بود برای تسک جدید، تو دیتابیس بدیم. باید یه فیلد جدید به  یکی جداول اضافه میکردیم که مقدار اون هم برابر با GUID بودبا توجه به مقداری که میگره، نوعش رو برابر با Unique در نظر گرفته بودیم.نکته ای که بود اینه که این فیلد میتونستن در بعضی موارد مقدار Null هم داشته باشه.همه چی داشت خوب پیش میرفت تا اینکه توی محیط تست خطاها شروع شدن، خطاها هم میگفتن که نمیشه ستون جدیدی با مقدار نال در این فیلد جدید به دیتابیس اضافه کرددر واقع مقدار Null رو Unique در نظر میگرفت و برای مقادیر جدید، جلوی ثبت سطر جدید با مقدار Null رو میگرفتبا کمی جستجو به Filter Index رسیدیم که راه حل مشکل ما بود که میتونید دربارش در داکیومنت زیر مطالعه کنیدhttps://docs.microsoft.com/en-us/sql/relational-databases/indexes/create-filtered-indexes?view=sql-server-ver15توسط این نوع از Index شما میتونید شرط بزارید که ایندکس در چه زمان هایی ساخته بشه. بطور مثال اگه یه فیلد دیگه فقط مقدار x رو داشت، ایندکس رو درست کن.پس ما شرطی گذشتیم تا فقط برای مقادیر غیر Null در این فیلد جدید ایندکس ساخته بشه. برای اینکار میتونید شبیه عکس زیر تو قسمت Filter هر Index شرطی که میخواید رو بزاریدالبته قبلش لینک بالا رو مطالعه کنید تا از پشتیبانی این نوع ایندکس در جدولی که میخواید مطمئن بشیدتو قسمت گفته شده کافیه شرطی که میخواید رو بزارید. بطور مثال :[ISR] IS NOT NULLیا اگه خواستید بصورت کوئری کار بالا رو انجام بدید میتونید بصورت زیر انجام بدیدCREATE UNIQUE NONCLUSTERED INDEX [FUIX_New_Re(ISR)] ON [new].[Re] ([ISR]) WHERE ([ISR] IS NOT NULL) ON [Tse]لینک مطلب در وبلاگاستفاده از unique index در ستون با مقدار null توسط Filter Index - روزمرگی های یک برنامه نویس (mhkarami97.ir)</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Tue, 16 Mar 2021 14:59:31 +0330</pubDate>
            </item>
                    <item>
                <title>موجیم، که آرامش ما عدم ماست (مهاجرت به لینوکس)(02)(پکیج منجر)</title>
                <link>https://virgool.io/mhkarami97/snap-package-manager-linux-z5m75hf0o58g</link>
                <description>قبل از همه اگه قسمت قبلی رو مطالعه نکردید رو لینک زیر کلیک کنید https://virgool.io/mhkarami97/uselinuxaswindowsuser-xdnzlofwm1ww اگه قسمت قبل رو مطالعه کرده باشید، اطلاع دارید که ما تونستیم لینوکس رو کامل نصب کنیماز کارهایی که بعد از نصب هر سیستم عاملی نیاز هست، نصب نرم افزارهای مورد نیاز هستتوی این قسمت لینوکس برای نرم افزارهایی که کاربرد عام دارن، خیلی خوب عمل کرده و کار خیلی راحت هستاما واسه بعضی چیزها پیچیدگی خاصی داره که بهش میرسیمتوی لینوکس یه چیزی هست به اسم Package Manager که برای نصب نرم افزارها استفاده میشهالبته ویندوز هم کمکم داره همچین چیزی رو درست میکنهپکیچ منجری که من استفاده کردم اسمش Snap بود که از لینک زیر میتونید راهنما و توضیحاتش رو ببینیدhttps://snapcraft.io/کار باهاش خیلی آسون هست و کافیه نرم افزاری که میخواید رو تو سایتش جستجو کنید و دستوری که داره رو توی ترمینال وارد کنیدترمینال هم توی لینوکس میشه همون CMD ویندوزمثلا برای نصب نرم افزاری شبیه آفیس کافیه دستور زیر رو بزنیدsudo snap install libreofficeدستور sudo میگه که این عمل باید بصورت Admin اجرا بشه، پس بعدش باید رمز ادمین رو وارد کنیدبقیش هم دستور پکیج منجر هستشخیلی از نرم افزارها رو به این صورت میتونید نصب کنید و خیلی هم آسون هست و کار خاصی نمیخواداما از این به بعد هست که مشکلها شروع میشه …چون من میخواستم SQL Server و .Net Core رو روی لینوکس نصب کنمو کمکم مشکلات از گوشه کنار میان بیرونپس با قسمت های بعدی رو دنبال کنید</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Tue, 16 Mar 2021 09:45:21 +0330</pubDate>
            </item>
                    <item>
                <title>موجیم، که آرامش ما عدم ماست (مهاجرت به لینوکس)(01)(شروع و نصب)</title>
                <link>https://virgool.io/mhkarami97/uselinuxaswindowsuser-xdnzlofwm1ww</link>
                <description>یه مدتی بود که می خواستم یه تجربه جدید یاد بگیرم و چیز جدیدی رو امتحان کنم، همچنین سیستم عامل ویندوز هم یکم واسم کند شده بود.یه چند باری هم خواسته بودم لینوکس رو نصب کنم ولی یبار هارد رو پاک کرده بودم و دفعه های بعد هم بعد نصب به مشکل خورده بودماما پیش خودم گفتم هرجور شده این دفعه باید هرجور شده این کار رو انجام بدمشروع به جستجو کردم تا ببینم کدوم توزیع از لینوکس رو نصب کنمدفعه های قبل Ubuntu رو دیده بودم ولی خیلی از ظاهرش خوشم نیومده بودیبار هم میخواستم Elementray Os رو نصب کنم که بعد از صفحه سیاه میموندبا جستجو تو اینترنت با توزیع Fedora آشنا شدم که طبق گفته بقیه برای برنامه نویس ها هم مناسب شدشروع به نصب کردم و برعکس دفعه قبل و با تجربه بدست اومده اینبار هارد رو پاک نکردم و با موفقیت تونستم نصبش کنم(در ادامه میگم چطور هاردتون رو پاک نکنید)اما بعد از بالا اومدن سیستم خیلی از ظاهرش خوشم نیومد، پس گفتم بزار همون Elementray Os که چندبار خواسته بودم نصب کنم و نشده بود رو نصب کنم و شاخ غول رو بشکنماول از همه اگه میخواید لینوکس نصب کنید باید یه مقدار از دیسک خودتون رو بصورت حافظه خالی دربیاریدبرای این کار رو My Computer راست کلیک کنید و به قسمت Manage برید و از سمت چپ گزینه Disk Management رو انتخاب کنیدبعدش رو درایوی که میخواید یه مقدارش رو جدا کنید راست کلیک کنید و Shrink رو انتخاب کنیدنگران ازدست رفتن اطلاعات هم نباشید، بعد از نصب لینوکس هم هرموقع خواستید میتونید دوباره این حافظه رو فرمت کنید و به درایو اصلی برگردونیدحالا نصب شروع میشه، کافیه روی فلش فایل ISO سیستم عاملی که دانلود کردید رو رایت کنیدhttps://itarfand.com/install-kali-linux-in-vmwareمراحل نصب خیلی آسون هست و نکته خیلی خاصی ندارهتا چند سال قبل لازم بود دستی پارتیشن بندی کنیدولی توی نسخه های جدید اون مقدار فضایی که خالی کردید بصورت اتومات شناسایی میشه و خودش هم میتونه پارتیشن بندی کنهاگه چندتا هارد دیسک هم داشته باشید، با اسم های جدا نشون داده میشنمثلا برای من Ada 4 بود که اولی هارد من و اون عدد هم فضای خالی هستشمشکلی که من دفعات قبل داشتم، اولیش بوت نشدن از روی فلشی که فایل لینوکس روش رایت شده بودبرای حل این مشکل به تنظیمات BIOS برید و Fast Boot رو خاموش کنیدیکی از مشکلات دیگه ای که داشتم، سیاه شدن صفحه بودبه این صورت که دفعه اول پس از نصب همه چی درست بود ولی وقتی یبار سیستم ریست میشد، دیگه صفحه سیاه بودبعضی وقتا هم کلا سیستم خاموش نمیشد که مجبور بودن Hard Shut Down کنمبرای حل این مشکل هم باید Secure Boot رو غیر فعال کنیدیه کار خیلی مهمی که بعد از نصب باید بکنید، نصب درایور کارت گرافیک هستبرای بقیه درایورها لازم نیست کار خاصی بکنید ولی این یکی خیلی مهم هست که یه قسمتی از مشکل صفحه سیاه به این هم مربوط میشهسیستم عاملی که من نصب کردم خودش یه App Center داشت که درایوها رو شناسایی میکرداگر هم یه توزیع دیگه نصب کردید کافیه از سایت سازنده کارت گرافیک، درایور مورد نظر رو دانلود کنیدپس تا این قسمت تونستیم سیستم خودمون رو بدون مشکل بالا بیاریمدر قسمت های بعد، به بقیه چالش هایی که بوجود اومد میپردازیمقسمت دوم:موجیم، که آرامش ما عدم ماست (مهاجرت به لینوکس)(02)(پکیج منجر) - itarfand (virgool.io) لینک مطلب در وبلاگموجیم، که آرامش ما عدم ماست (مهاجرت به لینوکس)(01)(شروع و نصب) - روزمرگی های یک برنامه نویس (mhkarami97.ir)</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Mon, 15 Mar 2021 10:08:40 +0330</pubDate>
            </item>
                    <item>
                <title>دیزاین پترن State در عمل</title>
                <link>https://virgool.io/mhkarami97/statedesignpatern-au75s3b9bsv0</link>
                <description>wikimediaدر قسمتی از پروژه ای که در حال نوشتن بودم و میخواستیم Fail Over رو بر روی قسمتی از سیستم پیاده سازی کنیم تا سیستم بصورت اتومات بتونه بعد از به خطا خوردن و یا مشکل دیگه ای، در سریعترین زمان ممکن یه نسخه دیگه کارش رو انجام بده.البته خود این fail over یه بحث جدا هست و توضیحات بیشتری میخواد که در آینده دربارش مینویسم، بصورت خلاصه این قسمت از برنامه در حال دریافت پیام های بورس هست و اون پیام ها رو برای بقیه سیستم در اختیار میزاره، اگه این قسمت قطع بشه میشه گفت کل سیستم میخوابه، پس اون fail over تو اینجا بدرد میخورهحالا برای این کار تو قسمتی از کد نیاز بود که بدونیم اگه سیستم اصلی خراب شد، سیستم جانشین از چه پیامی باید ادامه بده و با اون پیام ها چه کاری کنه.فرض کنید ما دوتا نسخه داریم با اسم های primary و secondary که اولی پیام ها رو به سیستم ارسال میکنه ولی دومی فقط پیام ها رو در دیتابیس ذخیره میکنه و هرموقع سیستم اول به مشکل خورد، بجاش ادامه میدهبرای اینکه secondary بتونه بجای سیستم اول ادامه بده، سه تا حالت مختلف ممکنه پیش میاد:درست تا جایی که سیستم اول پیام ها رو پردازش کرده بود، دریافت کرده باشهاز سیستم اول عقب تر باشیماز سیستم دوم جلوتر باشیمحالا تو هر کدوم از این حالت ها باید تصمیم متفاوتی بگیریماگه عقب تر باشیم باید پیام ها رو دریافت کنیم و داخل دیتابیس ذخیره کنیم و زمانی که درست به حالت سیستم اول رسیدیم، پیام ها رو ارسال هم کنیماگه جلوتر باشیم باید از دیتابیس بخونیم و وقتی به حالت سیستم اول رسیدیم، از بورس پیام ها رو دریافت کنیم.حالا برای این کار لازم بود که بدونیم دقیقا در چه حالتی هستیم که تو سناریوهای مختلف که بررسی کردیم، سه متغیر زیر به برنامه اضافه شدنpublic static bool IsPrimary { get; private set; }
public static bool IsBefotrPrimary { get; private set; }
public static bool IsFirstTime { get; private set; }تو قسمت نتیجه گیری هم با توجه به این متغیرها بصورت کد زیر تصمیم میگرفتیم که چیکار کنیم:private static int GetLastDispatchedMessageIdTypeCode()
        {
            int result;

            switch (FailOverService.IsBeforePrimary)
            {
                case true when FailOverService.IsPrimary:
                    result = PrimaryTypeCode;
                    break;
                
                case true when !FailOverService.IsPrimary:
                    result = SecondaryTypeCode;
                    break;
                
                case false when !FailOverService.IsPrimary:
                    result = SecondaryTypeCode;
                    break;
                
                case false when FailOverService.IsPrimary &amp;&amp; 
                            FailOverService.IsFirstTime:
                    result = PrimaryTypeCode;
                    break;
                
                case false when FailOverService.IsPrimary &amp;&amp; 
                            !FailOverService.IsFirstTime:
                    result = SecondaryTypeCode;
                    break;
                
                default:
                    throw new Exception(&amp;quotnot valid input&amp;quot);
            }

            return result;
}همونطور که میبینید کد بالا خیلی خوب نیست و خوانایی کمی هم داره.روشی که برای درست کردن کد بالا انجام دادم، استفاده از دیزاین پترن State بودhttps://sourcemaking.com/design_patterns/stateخلاصه کار به این صورت بود:یه کلاس با اسم Context به این صورت:public class Context
    {
        private State _state;

        public Context()
        {
            _state = new InitialState();
        }

        public void TransitionTo(State state)
        {
            Logger.WriteInformationLog($&amp;quotContext: Transition to {state.GetType().Name}&amp;quot);

            _state = state;
            _state.SetContext(this);
        }

        public FailoverReadingTypeEnum GetState()
        {
            return _state.Handle();
        }
}کلاس State به صورت زیر:public abstract class State
    {
        protected Context Context;

        public void SetContext(Context context)
        {
            Context = context;
        }

        public abstract FailoverReadingTypeEnum Handle();
}یه Enum با مقادیر زیرpublic enum FailoverReadingTypeEnum
    {
        None = 0,
        Primary = 1,
        Secondary = 2
}روش کار به این صورت هست که ما برای هر کدوم از حالت هایی که نیاز داریم یه کلاس جدید درست میکنیم که از State ارث بری کرده باشهبه این صورت:public class PrimaryState : State
    {
        public override FailoverReadingTypeEnum Handle()
        {
            Logger.WriteInformationLog($&amp;quotFailoverReadingTypeEnum change to : {FailoverReadingTypeEnum.Primary.ToString()}&amp;quot);
            
            return FailoverReadingTypeEnum.Primary;
        }
}برای استفاده هم کافی هست کلاس Context رو تو قسمتی که میخوایم New کنیم و در زمان هایی که لازم داریم State اون رو تغییر بدیم یا State فعلی رو بگیریمpublic FailOverService(ProcessorType processorType)
{
            _context = new Context();
}به این صورت میتونیم حالت رو تغییر بدیم:_context.TransitionTo(new PrimaryState());که ورودی همون کلاس هایی هستن که از State ارث بری کردنبرای دریافت حالت هم کافیه بصورت زیر عمل کنیمpublic static FailoverReadingTypeEnum GetReadingType()
{
            return _context.GetState();
}با این کار در درجه اول یکی از اون boolean ها برای دونستن حالت حذف شد و فقط دو مقدار IsPrimary و IsFirstTime باقی موندناون متد که توش از switch , case استفاده شده بود هم بصورت زیر در اومدprivate static int GetLastDispatchedMessageIdTypeCode()
{
            return (int) FailOverService.GetReadingType();
}لینک مطلب در وبلاگ اصلی :دیزاین پترن State در عمل - روزمرگی های یک برنامه نویس (mhkarami97.ir)</description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Sun, 14 Mar 2021 08:52:37 +0330</pubDate>
            </item>
                    <item>
                <title>شخصی سازی قالب انگولار NGX Admin (ویرایش قسمت های احراز هویت)</title>
                <link>https://virgool.io/mhkarami97/make-auth-customize-jjrokkqftt0j</link>
                <description>توی این قسمت آموزش شخصی سازی قسمت های احراز هویت مثل Login, Register رو آموزش میدم.توسط این قسمت میتونید ظاهر این صفحه ها رو شخصی سازی کنید و اونها رو به api برای ورود و عضویت وصل کنید.لینک مطلب:https://forum.itarfand.com/topic/143-%D8%B4%D8%AE%D8%B5%DB%8C-%D8%B3%D8%A7%D8%B2%DB%8C-%D9%82%D8%A7%D9%84%D8%A8-%D8%A7%D9%86%DA%AF%D9%88%D9%84%D8%A7%D8%B1-ngx-admin/بقیه قسمت ها:https://www.aparat.com/playlist/340299 https://www.aparat.com/v/xuI4r </description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Mon, 13 Apr 2020 22:01:04 +0430</pubDate>
            </item>
                    <item>
                <title>شخصی سازی قالب انگولار NGX Admin (افزودن فونت دلخواه)</title>
                <link>https://virgool.io/mhkarami97/add-custom-font-to-ngx-admin-theme-ble7s7lz1t4e</link>
                <description>قسمت قبلی رو میتونید توی لینک زیر ببینید: https://virgool.io/mhkarami97/customize-ngx-admin-panel-in-persian-fotyqi9hftao توی این قسمت آموزش اضافه کردن فونت فارسی به پنل رو آموزش میدم. https://www.aparat.com/v/3kwQg توضیحات بیشتر هم توی لینک در دسترس هست: https://forum.itarfand.com/topic/143-%D8%B4%D8%AE%D8%B5%DB%8C-%D8%B3%D8%A7%D8%B2%DB%8C-%D9%82%D8%A7%D9%84%D8%A8-%D8%A7%D9%86%DA%AF%D9%88%D9%84%D8%A7%D8%B1-ngx-admin/ </description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Tue, 07 Apr 2020 11:34:42 +0430</pubDate>
            </item>
                    <item>
                <title>شخصی سازی قالب انگولار NGX Admin (راست چین کردن)</title>
                <link>https://virgool.io/mhkarami97/customize-ngx-admin-panel-in-persian-fotyqi9hftao</link>
                <description>توی این سری از آموزش ها می خوام آموزش ویرایش کردن قالب NGX Admin که یک قالب Open Source که با Angular نوشته شده رو آموزش بدم.پروژه رو توی توی لینک زیر میتونید ببینید:https://github.com/akveo/ngx-adminیکی از ویژگی های خوب این قالب آماده بودن بیشتر امکاناتی که برای نوشتن یه پنل مدیریت استفاه میشه هست. بطور مثال این قالب یه صفحه اصلی کامل برای IOT داره و بیشتر امکاناتش هم ماژولار هست.نسخه ویرایش شده هم توی لینک زیر قرار میدم:https://github.com/MHKarami97/ngx-panelتوضیحاتش بیشتر هم توی لینک زیر هستش:https://forum.itarfand.com/topic/143-%D8%B4%D8%AE%D8%B5%DB%8C-%D8%B3%D8%A7%D8%B2%DB%8C-%D9%82%D8%A7%D9%84%D8%A8-%D8%A7%D9%86%DA%AF%D9%88%D9%84%D8%A7%D8%B1-ngx-admin/آموزش ها هم بصورت فیلم هستن که هم اینجا و هم توی آپارات میتونید دنبال کنید.https://www.aparat.com/playlist/340299اولین قسمت آموزش هم، آموزش راست چین کردن قالب هستش. https://www.aparat.com/v/lze0g </description>
                <category>mhkarami97</category>
                <author>محمد حسین کرمی</author>
                <pubDate>Thu, 02 Apr 2020 22:12:56 +0430</pubDate>
            </item>
            </channel>
</rss>