نظرات مطالب
پَرباد - آموزش پیاده‌سازی پرداخت آنلاین در دات نت - تنظیمات
روش بهینه سازی شده تنظیم پایگاه داده در نسخه ۲.۱.۰

Database Initializer

Database Initializer همانطور که از نامش پیداست، به شما کمک می‌کند پایگاه داده پَرباد را به هر صورتیکه در نظر دارید راه اندازی کنید.

هدف از افزودن Database Initializer ها

از آنجایی که Entity Framework، پایگاه‌های داده زیادی را پشتیبانی می‌کند و هر کدام از آنها دارای شرایط، ویژگی‌ها و محدودیت های خاص خود هستند، شما می‌توانید پایگاه داده مورد نظر خود را آنطور که در نظر دارید ایجاد کنید. برای مثال پایگاه داده Sqlite طبق اعلام خود تیم Entity Framework دارای محدودیت‌هایی برای Migration است. به همین دلیل این پایگاه داده را نمی‌توان مانند SQL Server به راحتی Migrate کرد.

مواردی که توسط Database Initializer‌ها قابل استفاده هستند شامل:

  • Create Database
  • Delete Database
  • Migrate Database
  • Seed Database

نمونه مثال جهت تنظیم پایگاه داده به روش جدید:
services.AddParbad()
           .ConfigureDatabase(builder =>
           {
              // Choose your database provider (SQL Server, MySql, Sqlite, etc.)
              builder.Use....
           })
           .ConfigureDatabaseInitializer(builder =>
           {
              builder.UseInitializer(async context =>
              {
                  await context.Database.EnsureDeletedAsync();

                  // OR
                  await context.Database.EnsureCreatedAsync();

                  // OR
                  await context.Database.MigrateAsync();
              });
           });

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

همچنین جهت نوشتن راحتتر تنظیمات، متدهایی برای ایجاد، حذف و Migrate محیا شده که می‌توانید مانند زیر از آنها استفاده کنید:
services.AddParbad()
           .ConfigureDatabase(builder =>
           {
              // Choose your Entity Framework provider (SQL Server, MySql, Sqlite, etc.)
              builder.Use....
           })
           .ConfigureDatabaseInitializer(builder =>
           {
              builder.CreateDatabase();

              // OR
              builder.DeleteAndCreateDatabase();

              // OR
              builder.CreateAndMigrateDatabase();
           });

نکته ۱: اگر هیچکدام از متد‌های کمکی بالا برای شما مناسب نیستند، از همان روش اول یعنی UseInitializer استفاده کنید.
نکته ۲: Database Initializer ها، به همان ترتیبی که اضافه شده‌اند، اجرا خواهند شد.
نکته ۳: جهت سادگی در Migrate کردن پایگاه داده، در هنگام تنظیم پایگاه داده مورد نظر خود می‌توانید از متد UseParbadMigrations استفاده کنید.
مثال:
services.AddParbad()
           .ConfigureDatabase(builder =>
           {
              // SQL Server
              builder.UseSqlServer("Connection String", options => options.UseParbadMigrations());
           })
           .ConfigureDatabaseInitializer(builder =>
           {
              builder.CreateAndMigrateDatabase();
           });

متد UseParbadMigrations معادل متد زیر است:
builder.UseSqlServer("Connection String", options => options.MigrationsAssembly("Parbad"));


نمونه مثال‌ها را همچنین می‌توانید در صفحه GitHub پروژه مشاهده کنید. 
مطالب
کار با Docker بر روی ویندوز - قسمت هفتم - مدیریت اجرای چندین کانتینر به هم وابسته
تا اینجا نحوه‌ی اجرای برنامه‌ها، وب سرورها و حتی بانک‌های اطلاعاتی را توسط داکر بررسی کردیم. در این قسمت می‌خواهیم یک برنامه و بانک اطلاعاتی مخصوص آن‌را داخل یک کانتینر اجرا کنیم و برای این منظور از ابزار ساده کننده‌ی docker-compose استفاده خواهیم کرد.


docker-compose چیست؟

فرض کنید برنامه‌ی ما، از یک قسمت منطق خود برنامه و قسمت دیگر بانک اطلاعاتی آن تشکیل شده‌است. در این حالت برای توزیع آن توسط کانتینرها، نیاز به دو کانتینر مجزا خواهد بود؛ یکی برای برنامه و دیگری برای بانک اطلاعاتی:
dockerrun --name db`
-d `
-p 3306:3306 `
-e MYSQL_ROOT_PASSWORD=my-secret-pw `
-v db:/var/lib/mysql`
mysql

dockerinspect db # extract ipaddress

dockerrun --name web `
-d `
-p 8080:80 `
-e MY_DB_PORT=3306 `
-e MY_DB_HOST=? `
-v /my/php/app:/usr/share/nginx/html `
nginx
تمام این دستورات را به همراه یک ` نیز مشاهده می‌کنید. این روشی است که از آن برای چندسطری کردن دستورات در PowerShell استفاده می‌شود.
- دستور اول مطابق توضیحات قسمت قبل، یک بانک اطلاعاتی MySQL را در پس زمینه، با نام db که در آن، پورت 3306 میزبان به پورت 3306 کانتینر نگاشت شده‌است و همچنین بانک اطلاعاتی آن در یک volume نامدار به نام db با مسیر نگاشت شده‌ی به /var/lib/mysql/ داخل کانتینر ایجاد می‌شود، اجرا می‌کند.
- دستور دوم کار استخراج اطلاعات این کانتینر را انجام می‌دهد که شامل آدرس IP آن نیز می‌باشد. از این IP در برنامه‌ی وب استفاده خواهیم کرد.
- دستور سوم مطابق توضیحات قسمت پنجم، یک وب سرور nginx را برای هاست یک برنامه‌ی PHP که در آن پورت 8080 میزبان به پورت 80 کانتینر نگاشت شده‌است و همچنین فایل‌های آن از مسیر /my/php/app/ میزبان به مسیر /usr/share/nginx/html/ داخل کانتینر نگاشت و تامین می‌شوند، اجرا می‌کند. در اینجا از پارامتر e برای تعریف یک سری متغیر محیطی مانند شماره‌ی پورت و IP کانتینر اجرا کننده‌ی mysql، استفاده شده‌است.

در این مثال دو کانتینر به هم وابسته را اجرا کرده‌ایم و برای اجرای کانتینر دوم، نیاز است حداقل IP کانتینر اول را دانست و در قسمت MY_DB_HOST مقدار دهی کرد. روش دیگری نیز برای مدیریت ساده‌تر اجرای چندین کانتینر به هم وابسته توسط ابزاری به نام docker-compose وجود دارد. اگر از Dockerfile (که آن‌را در قسمت پنجم معرفی کردیم) جهت ایجاد Imageهای سفارشی بکار می‌رود، فایل docker-compose.yml، کار خودکار سازی ایجاد و اجرای چندین کانتینر را انجام می‌دهد که با قالب YAML تعریف می‌شود:
version: '2'
services:
    db:
         image: mysql
         ports:
             -3306:3306
         environment:
             -MYSQL_ROOT_PASSWORD=my-secret-pw
         volumes:
             -db:/var/lib/mysql

    web:
         image: nginx
         ports:
             -8080:80
         environment:
             -MY_DB_PORT=3306
             -MY_DB_HOST=db
         volumes:
             -/my/php/app:/usr/share/nginx/html
همانطور که مشاهده می‌کنید، هرچند قالب آن اندکی متفاوت شده‌است، اما در اصل با دستورات docker ای که در ابتدا معرفی کردیم، تفاوتی ندارد. محتوای فوق را در یک فایل متنی ویژه به نام docker-compose.yml ذخیره و آن‌را به ابزار خط فرمان دیگری به نام docker-compose معرفی می‌کنیم.
در ابتدای این فایل، شماره نگارش قالب YAML مورد استفاده، مشخص شده‌است. در این نگارش، به کانتینرها، services گفته می‌شود که در اینجا دو سرویس db و web را مشاهده می‌کنید. در فایل‌های yml، فضاهای خالی و indentations مهم هستند و بر این اساس است که کانتینرها و سپس مشخصات این کانتینرها، تمیز داده می‌شوند.


راه اندازی TeamCity به کمک فایل docker-compose.yml آن

در اینجا محتویات فایل docker-compose.yml مخصوص راه اندازی TeamCity را مشاهده می‌کنید که از سه کانتینر تشکیل شده‌است و از بانک اطلاعاتی postgres استفاده می‌کند:
version: '2'
services:
    teamcity:
        image: sjoerdmulder/teamcity
        ports:
            - 8111:8111
    teamcity-agent:
        image: sjoerdmulder/teamcity-agent
        environment:
            - TEAMCITY_SERVER=http://teamcity:8111
    postgres:
        image: postgres
        environment:
            - POSTGRES_DB=teamcity
در این تنظیمات، پورت 8111 میزبان به پورت 8111 کانتینر teamcity نگاشت شده‌است. در ادامه teamcity-agent نیاز به IP این کانتینر را دارد (یک build-server است). زمانیکه چندین کانتینر را توسط فایل docker-compose.yml راه اندازی می‌کنیم، داکر یک شبکه‌ی ایزوله (private network) را نیز برای اینکار مهیا می‌کند. داخل این شبکه‌ی ایزوله، یک DNS سرور توکار نیز وجود دارد که امکان دسترسی به کانتینرهای مختلف را از طریق نام کانتینرهای آن‌ها میسر می‌کند. به همین جهت است که مقدار TEAMCITY_SERVER، به http://teamcity:8111 تنظیم شده‌است و دقیقا از نام کانتینر teamcity برای یافتن IP آن استفاده می‌کند. همچنین باید دقت داشت در این آدرس، عدد 8111 به پورت داخل کانتینر teamcity اشاره می‌کند و نه به پورت میزبان. کانتینرها از طریق آدرس IP و پورت خودشان با هم در تماس هستند. پورت میزبان 8111، صرفا جهت فراخوانی teamcity از طریق سیستم میزبان مشخص شده‌است.


در ادامه برای کار با آن، ابتدا این محتویات را به صورت یک فایل متنی docker-compose.yml ذخیره کنید. سپس از طریق خط فرمان به پوشه‌ی آن وارد شده و دستور docker-compose up را صادر کنید. docker-compose یکی دیگر از ابزارهای خط فرمان نصب شده‌ی به همراه داکر است و پارامتر up آن کار راه اندازی و اجرای کانتینرهای ذکر شده‌ی در فایل yml موجود را انجام می‌دهد. نام پوشه‌ای که این فایل در آن قرار دارد، به عنوان نام پروژه‌ی مشترک بین این کانتینرها در گزارشات آن مورد استفاده قرار می‌گیرد.
پس از صدور این فرمان، ابتدا تمام imageهای ذکر شده‌ی در فایل yml دریافت می‌شوند (سه image در اینجا) و هر سه کانتینر راه اندازی می‌شوند. اکنون می‌توان در سیستم میزبان به آدرس http://localhost:8111 مراجعه کرد و از برنامه‌ی teamcity استفاده نمود. البته صفحه‌ی ابتدایی آن کار تنظیمات بانک اطلاعاتی آن‌را انجام می‌دهد و جائیکه در مورد database type سؤال می‌پرسد می‌توان postgres را انتخاب کرد و سپس در ذیل آن مقدار database host را نیز postgres وارد می‌کنیم. علت آن‌را نیز پیشتر توضیح دادیم. postgres در اینجا نام کانتینر نیز هست و ذکر نام آن، با ذکر IP مرتبط با آن کانتینر، یکی است. نام بانک اطلاعاتی را teamcity وارد کنید (مطابق تنظیمات فایل yml فوق) و نام کاربری آن نیز postgres است؛ بدون کلمه‌ی عبور. البته می‌شد در فایل yml فوق، متغیر محیطی POSTGRES_PASSWORD=xyz را نیز تنظیم کرد و سپس از آن در اینجا استفاده نمود.


docker-compose و ایجاد شبکه‌های ایزوله

توسط دستور docker network ls می‌توان لیست شبکه‌های مجازی ایجاد شده‌ی توسط docker را مشاهده کرد (و همچنین سایر network adapters موجود). اگر این دستور را اجرا کنید، کارت شبکه‌ی مجازی متناظر با شبکه‌ی خصوصی teamcity_default را که پیشتر در مورد آن توضیح داده شد، می‌توانید مشاهده کنید. این teamcity در اینجا همان نام پروژه و یا در اصل نام پوشه‌ای است که فایل docker-compose را از آنجا اجرا کردیم.
برای دریافت اطلاعات بیشتری در مورد این کارت شبکه‌ی به خصوص، می‌توان دستور docker network inspect teamcity_default را صادر کرد. یکی از قسمت‌های خروجی این گزارش، لیست کانتینرهایی است که هم اکنون به این شبکه متصل هستند؛ که در اینجا teamcity و بانک اطلاعاتی آن است.
مزیت ایجاد یک شبکه‌ی خصوصی مخصوص کانتینرهای به هم پیوسته، علاوه بر سادگی تشکیل فایل docker-compose آن‌ها با اشاره‌ی به نام کانتینرها، بجای ذکر مستقیم آدرس IP هر کدام، ایزوله ساختن این شبکه، از شبکه‌ی پیش‌فرض docker و بالا بردن میزان امنیت سایر کانتینرهایی است که هم اکنون از آن شبکه استفاده می‌کنند.


docker-compose و ایجاد DNS Server توکار

همانطور که عنوان شد، در این شبکه‌ی خصوصی ویژه‌ی کانتینرهای به هم پیوسته که توسط docker-compse اجرا و مدیریت شده‌اند، می‌توان از نام containerها بجای آدرس IP آن‌ها استفاده کرد و این مورد با وجود یک DNS Server توکار در این شبکه میسر شده‌است. برای آزمایش بیشتر این قابلیت، ابتدا دستور docker ps را صادر می‌کنیم تا نام کانتینرهای در حال اجرا را بدست بیاوریم. سپس سعی می‌کنیم پروسه‌ی bash shell داخل کانتینر بانک اطلاعاتی را اجرا کنیم:
docker ps
docker exec -it teamcity_postgres_1 bash
#exit
استفاده از docker exec یک روش است برای دسترسی به shell این کانتینر در حال اجرا؛ روش دیگر، استفاده از خود docker-compse می‌باشد که در این حالت، کار با آن ساده‌تر است:
 docker-compose exec postgres bash
در اینجا نیازی به ذکر سوئیچ it نیست؛ چون مقدار پیش‌فرض آن است و همچنین دیگر نیازی به اجرای docker ps برای یافتن نام کانتینری هم نیست و مستقیما می‌توان از نام‌های سرویس‌هایی که در فایل docker-compose.yml تعریف شده‌اند، استفاده کرد.
پس از دسترسی به شل، دستور زیر را اجرا کنید:
#ping teamcity
#exit
مشاهده خواهید کرد که این کانتینر می‌تواند کانتینر دیگری را صرفا با ذکر نام آن، ping کند.

یک نکته: اگر بخواهیم از وضعیت بانک‌های اطلاعاتی postgres توسط برنامه‌ی psql آن گزارش بگیریم نیز روش اجرای آن به همین صورت است:
docker-compose exec postgres psql -U postgres
postgres=#\l
postgres=#\q


اتصال یک کانتینر خارج از شبکه‌ی مجازی ایجاد شده‌ی توسط docker-compose به آن

فرض کنید می‌خواهید کانتینر کم حجم لینوکس alpine را اجرا کنید و توسط آن به شبکه‌ی مجازی ایجاد شده‌ی توسط docker-compose متصل شوید. روش آن به صورت زیر است:
 docker run --name apline -it --rm --net teamcity_default alpine sh
در اینجا توسط سوئیچ net، می‌توان نام شبکه‌ی مجازی را که نیاز است به آن متصل شویم، ذکر کرد. نام teamcity_default نیز از طریق اجرای دستور docker netwrok ls بدست آمده‌است.
این دستور، کانتینر لینوکس alpine را در حالت interactive جهت اجرای shell آن، راه اندازی می‌کند. سپس به شبکه‌ی مجازی teamcity_default متصل می‌شود. برای آزمایش این اتصال، در این shell راه اندازی شده، دستور ping teamcity را می‌توان صادر کرد. همچنین از داخل کانتینر teamcity نیز می‌توان این کانتینر را با نام آن ping کرد.


راه اندازی مجدد کانتینرها توسط docker-compose

اگر دستور docker-compose ps را دقیقا در پوشه‌ای که فایل yml آن قرار دارد اجرا کنیم، می‌توان گزارشی را صرفا از وضعیت کانتینرهای مرتبط با این فایل yml بدست آورد. دستور docker ps، لیست وضعیت تمام کانتینرهای در حال اجرای موجود را بر می‌گرداند. اکنون فرض کنید یکی از کانتینرهای اجرای شده‌ی توسط docker-compose، دیگر در حال اجرا نیست. برای راه اندازی مجدد آن می‌توان از دستور docker-compose start teamcity-agent استفاده کرد. همچنین دستور docker-compose logs teamcity-agent، لیست آخرین لاگ‌های مرتبط با یک کانتینر را بر می‌گرداند که می‌تواند برای رفع اشکال بسیار مفید باشد.


حذف کانتینرهای به هم پیوسته‌ی ایجاد شده‌ی توسط docker-compose

در ذیل ابتدا یک سری دستور را جهت مشاهده‌ی وضعیت سیستم مشاهده می‌کنید. سپس دستور docker-compose stop، کار متوقف کردن کانتینرهای مرتبط با فایل yml آن‌را انجام می‌دهد. دستور docker-compose rm -v، علاوه بر حذف این کانتینرها، volumeهای بانک‌های اطلاعاتی مرتبط را نیز حذف می‌کند. در آخر دستور docker-compose down، شبکه‌ی مجازی مرتبط را نیز حذف خواهد کرد. سپس مجددا از وضعیت سیستم گزارش گیری شده‌است.
 docker ps
docker-compose ps
docker volume ls
docker network ls

docker-compose stop
docker-compose rm -v
docker-compose down

docker ps -a
docker volume ls
docker network ls


اجرای پروژه‌ی ASP.NET Core Music Store توسط docker-compose

پروژه‌ی معروف Music Store مایکروسافت را به همراه فایل docker-compose.windows.yml آن، در اینجا می‌توانید مشاهده کنید. محتوای این فایل نیز به صورت زیر است:
version: '3'
services:
  db:
    image: microsoft/mssql-server-windows-developer
    environment:
      sa_password: "Password1"
      ACCEPT_EULA: "Y"
    ports:
      - "1433:1433" # REMARK: This is currently required, needs investigation
    healthcheck:
      test: [ "CMD", "sqlcmd", "-U", "sa", "-P", "Password1", "-Q", "select 1" ]
      interval: 1s
      retries: 30
web:
    build:
      context: .
      dockerfile: Dockerfile.windows
    environment:
      - "Data:DefaultConnection:ConnectionString=Server=db,1433;Database=MusicStore;User Id=sa;Password=Password1;MultipleActiveResultSets=True"
    depends_on:
      - db
    ports:
      - "5000:5000"
در اینجا تعریف دو کانتینر را مشاهده می‌کنید:
- کانتینر db که بر اساس image مخصوص mssql-server-windows-developer راه اندازی می‌شود. تنظیمات آن نیز بسیار شبیه به مطلب «کار با Docker بر روی ویندوز - قسمت ششم - کار با بانک‌های اطلاعاتی درون Containerها» است که پیشتر در مورد آن بحث کردیم.
- کانتینر web آن که از فایل Dockerfile.windows برای build سپس publish و در آخر run خودکار این برنامه‌ی ASP.NET Core، کمک می‌گیرد. در اینجا context به پوشه‌ی جاری اشاره می‌کند. در قسمت تنظیمات بانک اطلاعاتی آن، استفاده‌ی از نام کانتینر db را در قسمت رشته‌ی اتصالی مشاهده می‌کنید. قسمت depends_on آن ترتیب اجرای این کانتینرها را مشخص می‌کند. یعنی ابتدا باید کانتینر db اجرا شود و سپس web.
محتوای فایل Dockerfile.windows آن نیز به صورت زیر است که بر اساس دستورات NET Core CLI. تهیه شده‌است:
FROM microsoft/dotnet-nightly:2.0-sdk-nanoserver
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
ENV NUGET_XMLDOC_MODE skip
ENV DOTNET_SKIP_FIRST_TIME_EXPERIENCE 1
RUN New-Item -Path \MusicStore\samples\MusicStore -Type Directory
WORKDIR app
ADD samples/MusicStore/MusicStore.csproj samples/MusicStore/MusicStore.csproj
ADD build/dependencies.props build/dependencies.props
ADD NuGet.config .
RUN dotnet restore --runtime win10-x64 .\samples\MusicStore
ADD samples samples
RUN dotnet publish --output /out --configuration Release --framework netcoreapp2.0 --runtime win10-x64 .\samples\MusicStore
FROM microsoft/dotnet-nightly:2.0-runtime-nanoserver
WORKDIR /app
COPY --from=0 /out .
EXPOSE 5000
ENV ASPNETCORE_URLS http://0.0.0.0:5000
CMD dotnet musicstore.dll
روش اجرای آن‌را نیز به صورت زیر بیان کرده‌است:
docker-compose -f .\docker-compose.windows.yml build
docker-compose -f .\docker-compose.windows.yml up
البته باید دقت داشت که اجرای فرمان up، به صورت خودکار کار build را هم انجام می‌دهد. پس از اجرای آن، برنامه را بر روی پورت 5000 می‌توانید مشاهده کنید.
نظرات مطالب
کوئری نویسی در EF Core - قسمت پنجم - اعمال تجمعی - بخش دوم
یک نکته‌ی تکمیلی
کتابخانه‌ی « linq2db » از window functions پشتیبانی می‌کند. می‌توان این کتابخانه را توسط « linq2db.EntityFrameworkCore » با EF-Core یکی کرد. برای کار با آن ابتدا نیاز است بسته‌ی نیوگت آن‌را نصب کنید:
dotnet add package linq2db.EntityFrameworkCore
سپس در ابتدای برنامه یکبار آ‌ن‌را فعال کنید:
LinqToDB.EntityFrameworkCore.LinqToDBForEFTools.Initialize();
LinqToDB.Data.DataConnection.TurnTraceSwitchOn();
پس از آن به صورت زیر می‌توان از Window functions در کوئری‌های معمولی EF-Core استفاده کرد:
var runningTotalCountForEachYear = context.Bookings
             .Select(booking => new
             {
                 booking.StartTime.Year,
                 RunningTotalCount =
                     Sql.Ext.Count(booking.StartTime)
                             .Over()
                             .OrderBy(booking.StartTime.Year)
                             .ToValue()
             })
             .OrderBy(result => result.Year)
             .Distinct()
             .ToLinqToDB()
             .ToList();
با این خروجی SQL:
SELECT DISTINCT
    DatePart(year, [booking].[StartTime]),
    COUNT([booking].[StartTime]) OVER(ORDER BY DatePart(year, [booking].[StartTime]))
FROM
    [Bookings] [booking]
ORDER BY
    DatePart(year, [booking].[StartTime])
نظرات مطالب
شروع به کار با EF Core 1.0 - قسمت 8 - بررسی رابطه‌ی Many-to-Many
لیست صفحه بندی شده‌ی تگ‌های مطلب اول
var post1Tags = context.BlogPosts
      .Where(blogPosts => blogPosts.Id == 1)
      .SelectMany(blogPosts => blogPosts.BlogPostsJoinTags)
      .Select(blogPostsJoinTags => blogPostsJoinTags.Tag)
      .Skip(0)
      .Take(10)
      .ToList();
با این خروجی SQL
SELECT   [blogPosts.BlogPostsJoinTags.Tag].[Id],
         [blogPosts.BlogPostsJoinTags.Tag].[Name]
FROM     [BlogPosts] AS [blogPosts]
         INNER JOIN
         [BlogPostsJoinTags] AS [blogPosts.BlogPostsJoinTags]
         ON [blogPosts].[Id] = [blogPosts.BlogPostsJoinTags].[BlogPostId]
         INNER JOIN
         [Tags] AS [blogPosts.BlogPostsJoinTags.Tag]
         ON [blogPosts.BlogPostsJoinTags].[TagId] = [blogPosts.BlogPostsJoinTags.Tag].[Id]
WHERE    [blogPosts].[Id] = 1
ORDER BY @@ROWCOUNT
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY;
نظرات مطالب
نکاتی در باب T-SQL
سلام.
بنظرم این فقط یه حقه کثیف هستش که مطلقا منظور از چنین SQL رو نمیشه بسادگی متوجه شد. منظورم روش اول در شماره 4 (بدست آوردن ماکزیموم دو عدد) و همونطوری که اینجا هم بهش اشاره شده، اگر مقدار جمع اون مقدار از Data Type اولیه بیشتر بشه، Arithmetic overflow رخ میده.

روش دوم رو هم میشه با IIF ساده‌تر نوشت:
DECLARE @Value1 DECIMAL(5,2) = 9.22
DECLARE @Value2 DECIMAL(5,2) = 8.34
SELECT IIF(@Value1 > @Value2, @Value1, @Value2) AS MaxColumn
یه روش دیگه هم هست، اونم اینکه بدین شکل با استفاده از VALUES مقادیر رو به Row‌ها بیاریم و با استفاده از MAX عدد بزرگتر رو انتخاب کنیم:

SELECT MAX(Col) FROM (VALUES (@Value1),(@Value2)) AS alias(Col)
موفق باشید.
نظرات مطالب
تولید پویای ستون‌ها در PdfReport
سلام آقای نصیری 
من تنطیمات اتصال بانک اطلاعاتی را انجام داده ام . اما باز با مشکل مواجه هستم .
کد‌های خودم رو خدمت شما ارسال میکنم . منو راهنمایی بفرمایید.
با تشکر

..MainTableDataSource(dataSource =>
             {
                 dataSource.SqlDataReader(
                    providerName: "System.Data.SqlClient",
                    connectionString: "Data Source=.\SQLEXPRESS;Initial Catalog=EFDB;Integrated Security=True",
                    sql: @"SELECT [id] as 'شماره', [Title] as 'نام', [Content] as 'تعداد مطالب', [Date] as 'تاریخ ارسال'
                           FROM [posts]
                           WHERE [NumberOfPosts]>=@p1",
                    parametersValues: new object[] { 10 }
                );
             })
پاسخ به بازخورد‌های پروژه‌ها
تولید پویای رشته Sql و ارسال پارامتر برای عملگر Like
دقیقا مانند مباحث کار با پارامترها در ADO.NET است:
command.Parameters.AddWithValue("@p3", "%test%");
در اینجا هم در کوئری می‌نویسید like @p3 و مقدار آن‌را درصد دار تعریف می‌کنید:
                dataSource.GenericDataReader(
                    providerName: "System.Data.SQLite",
                    connectionString: "Data Source=" + System.IO.Path.Combine(AppPath.ApplicationPath, "data\\blogs.sqlite"),
                    sql: @"SELECT [url], [name], [NumberOfPosts], [AddDate]
                               FROM [tblBlogs]
                               WHERE [NumberOfPosts]>=@p1 or [name] like @p2",
                    parametersValues: new object[]
                    {
                        10 /* 1st parameter's value */, 
                        "%blog%" /* 2nd parameter's value */
                    }
                );
بازخوردهای پروژه‌ها
تعداد کانکشن ها
با تشکر از این ابزار قدرتمند . بنده از Glimpse استفاده میکنم ولی DNTProfile واقعا کاربردی و  عالی است .
عدد مقابل Byconnection  آیا نشان دهنده تعداد کانکشن‌های باز است یا کل کانکشن هایی که برای یک عملیات انجام شده است ؟ در DNTProfile عدد 3 را دارم ولی با کوئری زیر تعداد دو کانکشن باز دارم :
SELECT 
    DB_NAME(dbid) as DBName, 
    COUNT(dbid) as NumberOfConnections,
    loginame as LoginName
FROM
    sys.sysprocesses
WHERE 
    dbid > 0
GROUP BY 
    dbid, loginame
و سوال دوم وقتی یک کاکشن را  انتخاب می‌کنم در تب زیر آن SQL Command ی مشاهده نمی‌شود  و سوال آخر هر چند ثانیه (حدود 30 ثانیه) یک بار مقدار By connection  اضافه می‌شود در صورتی که هیچ عمل خاصی در فرم اتفاق نیفتاده است.
ممنون میشوم در صورت امکان  راهنمایی بفرمایید .
اشتراک‌ها
ارسال اطلاعات به پراسیجر SQL‌ از طریق XML
بارها قصد ارسال اطلاعات با تعداد رکوردهای بالا را به SQL را داشته اید. برای این منظور یا باید به صورت رکورد، رکورد ارسال اطلاعات نمایید که مشکلات فراوانی مثل سرعت انتقال اطلاعات و هندل کردن قطعی سیستم در حال ارسال و غیره وجود دارد. برای حل این موضوع پیشنهاد می‌شود از ارسال اطلاعات از طریق XML اقدام نمایید و اطلاعات را در سمت SQL ارسال و یا تغییر دهید.
برای این منظور یک string ‌به صورت زیر در محیط نرم افزار ایجاد می‌شود و در سمت SQL هم پراسیجری با ورودی Text ایجاد می‌شود و سپس از طریق دستورات زیر می‌توانید Table‌معادل XML ارسالی را دریافت نمایید.
 DECLARE @xml xml
SET @xml = N'<polist>
               <po ponumber="100" podate="2008-09-10" />
               <po ponumber="101" podate="2008-09-11" />
             </polist>'
SELECT
 doc.col.value('@ponumber', 'nvarchar(10)') ponumber
,doc.col.value('@podate', 'datetime') podate 
FROM @xml.nodes('/polist/po') doc(col)
ارسال اطلاعات به پراسیجر SQL‌ از طریق XML
بازخوردهای پروژه‌ها
تولید پویای رشته Sql و ارسال پارامتر برای عملگر Like
با سلام
با استفاده از کد زیر که sql آن به صورت پویا تولید شده است :
.MainTableDataSource(dataSource =>
{
dataSource.GenericDataReader(
providerName : "System.Data.SqlServerCe.4.0",
connectionString : @"Data Source=data.sdf;password=******",
sql : "Select [VoucherRows].[Description] AS [Description],[VoucherRows].[Creditor] AS [Creditor],[VoucherRows].[Debtor] AS [Debtor],[Vouchers].[Number] AS [Number],
[Vouchers].[SubmitDate] AS [SubmitDate] 
From [VoucherRows] AS [VoucherRows],[Vouchers] AS [Vouchers]  
Where  [Vouchers].[Id]  =  [VoucherRows].[VoucherId]  And  [Vouchers].[Number]  >=  @p1  And  [Vouchers].[Number]  <=  @p2  And 
 [Vouchers].[Description]  Like  '%' + @p3 + '%'    Order By [Vouchers].[SubmitDate] DESC,[Vouchers].[Number] ASC",
parametersValues : new object[] {50,100,"مقدار"}
);
})
میخواهم گزارشی را تهیه کنم ولی برای پارامتر سوم که از عملگر Like استفاده میکند، خطای Input string was not in correct ... را می‌گیرم. 
مشکل از کجاست؟رشته Sql تولید شده؟ یا نحوه ارسال پارامتر؟