کند اجرا شدن کوئری در Entity Framework و تغییر نوع پارامتر رشته‌ای در SQL نهایی

در Entity Framework بصورت پیش‌فرض متغیرهای string به پارامتری از نوع nvarchar(4000) در SQL تولید شده نهایی تبدیل می‌شود.

بعنوان مثال کوئری زیر را در نظر بگیرید:

using (var db = new SampleContext())
{
    var year = "1392";
    var query = from list in db.ListSend
                where list.AccountId == 2 && list.SendDate.Substring(1, 10) == year
                select list;
}

 

این کوئری به کد SQL زیر تبدیل خواهد شد:

exec sp_executesql N'SELECT 
	[Extent1].[AccountId] AS [AccountId],
	[Extent1].[SendDate] AS [SendDate]
	FROM [dbo].[ListSend] AS [Extent1]
	WHERE ([Extent1].[AccountId] = @p__linq__0) AND ((SUBSTRING([Extent1].[SendDate], 0 + 1, 4)) = @p__linq__1)
,N'@p__linq__0 int,@p__linq__1 nvarchar(4000)',@p__linq__0=2,@p__linq__1='1392'

اجرای این کوئری بر روی داده‌های با تعداد بالا گاهی تا حدود 30 ثانیه طول می‌کشد! علت اصلی این کند اجرا شدن به تبدیل نوع رشته‌ای متغیر SendDate به nvarchar برمی‌گردد. برای رفع این مشکل اگر نوع پارامتر SendDate به نوع varchar(8000) تبدیل شود این کوئری بدون تأخیر اجرا می‌شود.

 

تبدیل نوع پارامتر رشته‌ای در Entity Framework

بمنظور اینکه متغیر رشته‌ای در کوئری Entity Framework به نوع varchar(8000) تبدیل شود از کلاس EntityFunctions که در فضای نام  System.Data.Objects قرار دارد به شکل زیر استفاده می‌کنیم:

EntityFunctions.AsNonUnicode(year)

 

در نهایت کد ما به شکل زیر خواهد بود:

using (var db = new SampleContext())
{
    var year = "1392";
    var query = from list in db.ListSend
                where list.AccountId == 2 && list.SendDate.Substring(1, 10) == EntityFunctions.AsNonUnicode(year)
                select list;
}

 

خروجی SQL کوئری فوق بدین شکل خواهد بود:

exec sp_executesql N'SELECT 
	[Extent1].[AccountId] AS [AccountId],
	[Extent1].[SendDate] AS [SendDate]
	FROM [dbo].[ListSend] AS [Extent1]
	WHERE ([Extent1].[AccountId] = @p__linq__0) AND ((SUBSTRING([Extent1].[SendDate], 0 + 1, 4)) = @p__linq__1)
,N'@p__linq__0 int,@p__linq__1 varchar(8000)',@p__linq__0=2,@p__linq__1='1392'

 

راه‌اندازی مجدد مودم ADSL از طریق کدنویسی

یکی از معایب اینترنت‌های ADSL معمولی عدم پایداری اتصال به اینترنت می‌باشد. یعنی زمانی که مودم ADSL برای ساعات طولانی مدت (معمولاً بیشتر از 24 ساعت) روشن باشد، غالباً اینترنت قطع شده و نیاز به راه‌اندازی مجدد مودم برای ایجاد سشن جدید و اتصال مجدد به اینترنت می‌باشد.

چقدر خوب بود اگر می‌شد این کار بصورت اتوماسیون انجام می‌گرفت.

برای انجام این کار قطعه کدی تهیه کرده‌ام که بصورت متوالی اتصال به اینترنت را آزمایش کرده و در صورت عدم اتصال به اینترنت مودم را خاموش و روشن می‌کند.

نکته‌ای که در اینجا حائز اهمیت است نحوه خاموش و روشن کردن مودم از طریق کدنویسی می‌باشد.

غالباً برای انجام اجرای دستورات مودم یا روترها از Telnet استفاده می‌شود. به این شکل که از طریق خط فرمان با دستور Telnet به مودم متصل شده و پس از وارد کردن نام کاربری و رمز عبور، دستور مورد نظر را مثل دستور Reboot رای در خط فرمان تایپ کرده و اینتر زده و بدین ترتیب مودم راه‌اندازی مجدد می‌شود.

بعلت اینکه جهت Telnet کردن به مودم نیاز به وارد کردن نام کاربر و رمز عبور در خط فرمان می‌باشد، از امکانات زبان پایتون استفاده خواهیم کرد.

نحوه اتصال به مودم از طریق برنامه‌نویسی

ابتدا نصاب پایتون برای ویندوز را از این آدرس دریافت کرده و آن را نصب نمایید. نصب پایتون نکته‌ی خاصی ندارد.

پس از نصب پایتون قطعه کد زیر را در فایلی با پسوند "py" ذخیره می‌‌کنید.

برای تست اتصال به اینترنت از متد زیر استفاده می‌کنیم:

def pingHost():
    hostname = "www.google.com"
    response = os.system("ping " + hostname)

    if response == 0:
      return True
    else:
      return False

این قطعه کد یک Ping به یک هاست مانند گوگل زده و از این طریق وضعیت اتصال به اینترنت را تشخیص می‌دهد.

اگر به تعداد maxTry اتصال به اینترنت انجام نشود، توسط متد زیر مودم مجدداً راه‌اندازی می‌شود:

def rebootModem():
    try:
        print("Rebooting modem...")
        HOST = "192.168.1.1"
        user = b"admin"
        password = b"password"

        tn = telnetlib.Telnet(HOST)

        tn.read_until(b"Login: ")
        tn.write(user + b"\n")
        tn.read_until(b"Password: ")
        tn.write(password + b"\n")
        tn.read_until(b"> ")
        tn.write(b"reboot\n\n")
    except:
        print("Error!")

توسط این متد ابتدا به آی‌پی مودم که بصورت پیش‌فرض 192.168.1.1 می‌باشد، Telnet کرده و منتظر خط فرمان برای درخواست نام کاربری می‌ماند، یعنی منتظر مانده تا در خط فرمان عبارت "Login:" دیده شود:

        tn.read_until(b"Login: ")

پس از مشاهده عبارت Login برنامه نام کاربری را ارسال کرده و فشردن کلید اینتر را توسط کاراکتر "\n" شبیه‌سازی می‌کند:

        tn.write(user + b"\n")

بهمین ترتیب منتظر درخواست کلمه رمز شده و کلمه رمز را ارسال می‌کند و پس از ظاهر شدن اعلان خط فرمان مودم یعنی پس از دیده شدن کاراکتر "<" دستور "reboot" صادر شده و فشرده شدن کلید اینتر شبیه‌سازی می‌شود:

        tn.read_until(b"> ")
        tn.write(b"reboot\n\n")

کد کامل برنامه

import os
import time
import telnetlib
import datetime

maxTry = 3
shortDelay = 10
longDelay = 300
tryCount = 0

def pingHost():
    hostname = "www.google.com"
    response = os.system("ping " + hostname)

    if response == 0:
      return True
    else:
      return False

def rebootModem():
    try:
        print("Rebooting modem...")
        HOST = "192.168.1.1"
        user = b"admin"
        password = b"password"

        tn = telnetlib.Telnet(HOST)

        tn.read_until(b"Login: ")
        tn.write(user + b"\n")
        tn.read_until(b"Password: ")
        tn.write(password + b"\n")
        tn.read_until(b"> ")
        tn.write(b"reboot\n\n")
    except:
        print("Error!")

delayTime = longDelay

while True:
    if(pingHost() == False):
        delayTime = shortDelay
        if(tryCount == maxTry):
            rebootModem()
            tryCount = 0
            delayTime = longDelay
        else:
            tryCount+=1
    else:
        delayTime = longDelay
    time.sleep(delayTime)

اجرای برنامه

جهت اجرای برنامه به دو روش می‌توانید اقدام کنید:

1- برنامه IDLE که در مسیر All Program>Python x.x قرار دارد را اجرا کنید. از منوی File>Open فایل برنامه را بازکرده و کلید F5 را جهت اجرا بفشارید.

2- از طریق خط فرمان زیر:

C:\PythonXX\python.exe RebootModem.py

 

کد کامل برنامه را در قالب فایل پایتون دریافت کنید:

بهینه‌سازی آدرس‌های وبلاگ مبتنی بر Blogengine.NET

در پست قبلی به دلایل استفاده از حروف کوچک در آدرس‌های وب‌سایت اشاره شد. حال مسئله‌ای که وجود دارد این است که در حالتی که شما از سیستم‌های مدیریت محتوا (CMS) و یا سیستم‌های مدیریت وبلاگ (Blog Engine) استفاده می‌کنید چطور این امکان را به سایت خود اضافه کنید. بعنوان مثال افزودن این امکان را برای سیستم مدیریت وبلاگ Blogengine.NET بررسی خواهیم کرد.


آدرس‌های پیش‌فرض در Blogengine شامل حروف بزرگ می‌باشد. چون Blogengine بر پایه‌ی دات‌نت طراحی شده‌است و بر روی وب‌سرور IIS اجرا می‌شود، می‌توان از امکانات IIS جهت تبدیل آدرس‌ها به حروف کوچک استفاده کرد.


برای این منظور از ماژول URL Rewrite استفاده خواهیم کرد. URL Rewrite ماژولی است که توسط آن می‌توانید آدرس‌های درخواستی وب‌سایت خود را به آدرس دلخواهتان تغییر دهید.
آدرس دریافت ماژول URL Rewrite
پس از دریافت ماژول آن را نصب کنید و سپس کد زیر را به فایل وب‌کانفیگ وبلاگ اضافه کنید.

<system.webServer>
  <rewrite>
    <rules>
      <rule name="LowerCaseRule" stopProcessing="true">
        <match url="[A-Z]" ignoreCase="false" />
        <action type="Redirect" url="{ToLower:{URL}}" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

توضیح کد:
این کد تمامی آدرس‌های درخواستی را به حروف کوچک (Lowercase) تبدیل می‌کند.

یک مشکل بزرگ!
احتمالاً پس از اضافه کردن کد فوق قسمت‌هایی از وبلاگ شما از کار خواهد افتاد. خصوصاً بخش‌های مدیریت وبلاگتان از قبیل مشاهده لیست پست‌ها و نظرات و ...
این مشکل بخاطر این است که یک سری از سرویس‌های مدیریت وبلاگ حساس به حروف کوچک و بزرگ هستند.
برای رفع این مشکل باید صفحاتی که شامل صفحات مدیریت وبلاگتان می‌باشند، یعنی صفحاتی که پس از لاگین کردن با حساب مدیر وبلاگ قابل مشاهد هستند را از قسمت تغییر آدرس مستثنی کرد. بعلت اینکه این صفحات، صفحات عمومی نیستند پس نیازی هم به رتبه‌بندی این صفحات در موتورهای جستجو نیست.
بعلت اینکه نام کاربر در آدرس صفحات مدیریت وبلاگ وجود دارد، بعنوان مثال در آدرس http://www.weblog.com/admin/Posts.aspx نام کاربر (admin) وجود دارد، پس می‌توان تنظیم کرد که تمامی صفحاتی که در آنها کلمه "/admin/" و یا کلمه "/api/" وجود دارد نادیده گرفته شوند.
برای انجام این کار کد را به این شکل تغییر دهید:

<system.webServer>
  ...
  <rewrite>
    <rules>
      <rule name="LowerCaseRule" stopProcessing="true">
        <match url="[A-Z]" ignoreCase="false" />
        <conditions>
          <add input="{URL}" matchType="Pattern" pattern="^.*/admin/.*$" ignoreCase="false" negate="true" />
          <add input="{URL}" matchType="Pattern" pattern="^.*/api/.*$" ignoreCase="false" negate="true" />
        </conditions>
        <action type="Redirect" url="{ToLower:{URL}}" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>


اجبار به استفاده از www در آدرس‌ها
یکی دیگر از مواردی که باعث اختلاف در آدرس‌های مشابه سایت می‌شود وجود یا عدم وجود www در آدرس سایت می‌باشد. برای افزودن خودکار www به تمامی آدرس‌های سایت نیز می‌توانید از ماژول URL Reweiter استفاده کرد.
برای این کار قطعه کد زیر را نیز به وب کانفیگ وبلاگ یا سایت خود اضافه کنید.
<system.webServer>
  ...
  <rewrite>
    <rules>
      ...
      <rule name="Add www" patternSyntax="Wildcard" stopProcessing="true">
        <match url="*" />
        <conditions>
          <add input="{HTTP_HOST}" pattern="www.yoursite.com" negate="true" />
        </conditions>
        <action type="Redirect" url="http://www.yoursite.com/{R:1}" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>


حال اگر آدرس وبلاگ و یا سایت بصورت yoursite.com وارد شود بصورت خودکار به آدرس www.yoursite.com منتقل خواهد شد.

دلایل عدم استفاده از حروف بزرگ در آدرس‌های وب‌سایت

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

http://www.example.com/about
http://www.example.com/About

هر دو آدرس به یک صفحه مشخص اشاره می‌کنند.  اما آدرسی که در آن تماماً حروف کوچک استفاده شده است، بهتر است. در ادامه به دلایل این مسئله می‌پردازیم.

پردازش آدرس‌ها در سرورهای مختلف متفاوت است

اگر وب‌سایت شما بر روی یک سرور ویندوزی باشد، هر دو آدرس http://www.example.com/about و http://www.example.com/About یکسان درنظر گرفته شده و به یک صفحه ارجاع داده می‌شوند. ولی اگر سرور وب‌سایت شما لینوکسی باشد، آنگاه هر دو آدرس، دو آدرس مجزا در نظر گرفته می‌شود. یعنی یکی از آدرس‌ها به صفحه مورد نظر ارجاع داده می‌شود و آدرس دوم با خطای 404  (صفحه یافت نشد)  مواجه می‌شود!


داشتن دو آدرسی که به یک صفحه  اشاره می‌کند برای رتبه‌بندی موتورهای جستجو مناسب نمی‌باشد

همانطور که قبلاً اشاره کردیم اگرچه در سرورهای ویندوزی هر دو آدرس http://www.example.com/about و http://www.example.com/About به یک صفحه واحد ارجاع داده می‌شود اما موتورهای جستجو این دو آدرس را دو صفحه مجزا در نظر می‌گیرند که این از لحاظ رتبه‌بندی صفحه مورد نظر در موتورهای مناسب نیست و رتبه صفحه موردنظر کمتر از مقدار واقعی آن خواهد شد.


نتیجه‌گیری:

حتماً در حین طراحی و یا راه‌اندازی وب‌سایتتان این مسئله را در نظر داشته باشید که تمامی آدرس‌های وب‌سایتتان از حروف کوچک تشکیل شده باشد


چاپ رکورد جاری توسط FastReport

اگر می‌خواهید که توسط FastReport در یک جدول فقط رکورد جاری را چاپ کنید و بجای رکورد جاری، رکورد اول و یا همه‌ی رکوردها چاپ می‌شوند به احتمال زیاد کامپوننت‌های FastReport بر روی فرمی که درحال کار با آن هستید قرار دارد.
ممکن است بخواهید از قطعه کد زیر برای این منظور استفاده کنید ولی این روش هم جواب نمی‌دهد:
frxDBDataset.RangeBegin := rbCurrent;
frxDBDataset.RangeEnd := reCurrent;
frxReport.ShowReport;

راه حل آن این است که تمامی کامپوننت‌ها FastReport را به یک DataModule منتقل کرده و برای چاپ یک وهله از این DataModule را ایجاد کرده و اقدام به چاپ نمایید. در این حالت مشکل چاپ رکورد جاری وجود نخواهد داشت.