مطالب
نحوه استفاده از TransactionFlow در WCF
شش مرحله برای ایجاد WCFTransactions  در WCF 
 مقدمه و هدف:

هدف از مطلب  فوق اجرا نمودن عملیات Insert، Update و غیرو... بوسیله چندین Connection  در یک Transaction  در زمان اجرای سرویسهای WCF  میباشد. برای پیاده سازی و شرح Transaction ، سه پروژه ایجاد می‌نماییم. دو پروژه WCF  سرویس و یک پروژهClient ، هر سه پروژه را در یک Solution  به نام WCFTransaction  اضافه می‌نماییم. در هر دو پروژه WCF  بطور جداگانه Connection  رویDatabase  ایجاد می‌نماییم. سپس سعی می‌کنیم بوسیله Transaction  عملیات Insert  هر دو Service  را کنترل نماییم. بطوریکه اگر یکی از Service ‌ها در زمان عملیات Insert  دچار مشکل شود. دیگری نیز Commit  نگردد. به عبارتی در قدیم نمی‌توانستیم بیش از یک Connection  در یک Transaction  ایجاد نماییم. اما بوسیله Transactionscope ، انجام عملیات Insert، Update و غیرو...  بوسیله چندین Connection   به یکDatabase  بطور همزمان در یک Transaction  فراهم شده است. برای نمایش دادن عملیات Rollback  نیز،به عمد خطایی ایجاد می‌کنیم،تا نحوه Rollback  شدن در Transaction  را مشاهده نماییم.

سعی شده است پیاده سازی و استفاده از  Transaction در شش مرحله انجام شود.

مرحله اول: ایجاد دو پروژه WCFService و یک پروژه Client جهت فراخوانی (Call) کردن سرویسها

در این مرحله همانطور که از قیل نیز توضیح داده شده است، دو پروژه WCF  به نامهای WCFService1  و WCFService2  ایجاد شده است و یک پروژه Client  به نام WCFTransactions  نیز ایجاد می‌کنیم.

مرحله دوم : افزودن   Attribute ی به نام   TransactionFlow به  Interface سرویسها.

در این مرحله در Interface  هریک از سرویس‌ها متد جدیدی به نام UpdateData  اضافه می‌نماییم. که عملیات Insert into  درون Database  را انجام می‌دهد. حال بالای متد UpdateData   از صفت TransactionFlow  استفاده می‌نماییم. تا قابلیت Transaction  برای متد فوق فعال گردد و متد فوق اجازه می‌یابد از Transaction  استفاده نماید.

<ServiceContract()> _
Public Interface IService1

    <OperationContract()> _
    Function GetData(ByVal value As Integer) As String

    <OperationContract()> _
    Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType

    <OperationContract()> _
    <TransactionFlow(TransactionFlowOption.Allowed)> _
     Sub UpdateData()

End Interface

مرحله سوم:

در این مرحله متد UpdateData  را پیاده سازی می‌نماییم. بطوریکه یک Insert Into  ساده در Database  انجام می‌دهیم.و بالای متد فوق نیز کد زیر را می‌افزاییم.

 <OperationBehavior(TransactionScopeRequired:=True)> 

کد متد UpdateData   

   <OperationBehavior(TransactionScopeRequired:=True)> _
    Public Sub UpdateData() Implements IService1.UpdateData
        Dim objConnection As SqlConnection = New SqlConnection(strConnection)
        objConnection.Open()
        Dim objCommand As SqlCommand = New SqlCommand("insert into T(ID,Age) values(10,10)", objConnection)
        objCommand.ExecuteNonQuery()
        objConnection.Close()
End Sub

مرحله دوم و سوم را برای Service دوم نیز تکرار می‌نماییم.

مرحله چهارم:

در این مرحله  TransactionFlow  را در Web.Config  دو سرویس فعال می‌نماییم. تا قابلیت استفاده از  TransactionFlow   برای سرویسها نیز فعال گردد. نحوه فعال نمودن بصورت زیر میباشد:

برای  WCFService1خواهیم داشت:

<bindings>
                <wsHttpBinding>
                                <binding name="TransactionalBind" transactionFlow="true"/>
                </wsHttpBinding>
</bindings>
و در ادامه داریم:
<endpoint address="" binding="wsHttpBinding" 
bindingConfiguration="TransactionalBind" 
contract="WcfService1.IService1">

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

<bindings>
                <wsHttpBinding>
                                <binding name="TransactionalBind" transactionFlow="true"/>
                </wsHttpBinding>
</bindings>

و در ادامه داریم:

<endpoint address="" binding="wsHttpBinding" 
bindingConfiguration="TransactionalBind" 
contract="WcfService2.IService1">

مرحله پنجم:

در این مرحله دو سرویس فوق را به پروژه  WCFTransactions  اضافه نموده و قطعه کد زیر را درون فرم Load  می‌نویسیم.

Private Sub frmmain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Using ts As New TransactionScope(TransactionScopeOption.Required)
            Try
                Dim obj As ServiceReference1.Service1Client = New ServiceReference1.Service1Client()
                obj.UpdateData()
                Dim obj1 As ServiceReference2.Service1Client = New ServiceReference2.Service1Client()
                obj1.UpdateData()
                ts.Complete()

            Catch ex As Exception
                ts.Dispose()
            End Try

        End Using
End Sub


پس از اجرای برنامه دو رکورد در جدول درج خواهد شد.

مرحله ششم:

حال برای RollBack   کردن کل عملیات و مشاهده آنها کافیست در یکی از متدهای UpdateData  یک  Throw Exception  ایجاد نماییم.

سعی می‌کنیم با کمی تغییر در متد UpdateData در WCFService2 ، خطایی ایجاد شود، تا نحوه RollBack را مشاهده نماییم.

Public Sub UpdateData() Implements IService1.UpdateData
        Throw New Exception()
        Dim objConnection As SqlConnection = New SqlConnection(strConnection)
        objConnection.Open()
        Dim objCommand As SqlCommand = New SqlCommand("insert into T(ID,Age) values(101,101)", objConnection)
        objCommand.ExecuteNonQuery()
        objConnection.Close()
End Sub

فقط کد زیر به متد UpdateData اضافه شده است:

Throw New Exception()

و در رویداد Load  فرم نیز پیاده سازی آن بشکل زیر خواهد بود:


Using ts As New TransactionScope(TransactionScopeOption.Required)
            Try
                Dim obj As ServiceReference1.Service1Client = New ServiceReference1.Service1Client()
                obj.UpdateData()
                Throw New Exception("There was Error")
                Dim obj1 As ServiceReference2.Service1Client = New ServiceReference2.Service1Client()
                obj1.UpdateData()
                ts.Complete()

            Catch ex As Exception
                ts.Dispose()
            End Try
 End Using 

وقتی برنامه را اجرا نمایید، مشاهده می‌کنید که هیچ رکوردی دورن دیتابیس درج نشده است.

بسبار مهم: برای اینکه بتوانید بصورت Distibuted  عملیات Transaction  را انجام دهید می‌بایست تنظیماتی را روی سرور که دیتایس و سرویسها و کامپیوتر کلاینت انجام دهید که بصورت زیر می‌باشد:

نحوه تنظیم:

1- سرویسDistribute Transaction Coordinator  را روی هر دو Server‌های WCFService ، Database و کامپیوتر کلاینت، Start می‌نماییم.    

البته در شرایطی که Service‌های WCF و برنامه Client و Database روی یک سیستم باشد، تنظیمات فوق فقط روی همان سیستم انجام می‌شود.

برای دسترسی به قسمت Service ‌های Windows  ابتدا Administrative Tools  و سپس Service   را باز نمایید و روی Start کلیک کنید.

2- در ادامه روی MY Computer کلیک راست نموده و تب MSDTC را انتخاب نمایید:

در ادامه روی Security Configuration  کلیک نمایید. تا فرم زیر نمایش داده شود.


مطمئن شوید که آیتمهای زیر انتخاب شده باشند:

· Network DTC Access

· Allow Remote Clients

· Allow Inbound

· Allow Outbound

· Enable Transaction Internet Protocol(TIP) Transactions 

سپس با OK کردن Service،سرویس بطور خودکار Restart می‌شود.
در ضمن اگر از SQL Server 2000 استفاده می‌نمایید. لازم است تنظیم زیر را انجام دهید.
روی SQL Server Service Manager کلیک نموده و کامبوی Service را Dropdown نمایید و Distribute Transaction Coordinator  را انتخاب کنید. اما برای ورژن‌های بالاتر از SQL Server 2000 نیاز به انتخاب Distribute Transaction Coordinator  نمی‌باشد.
امیدوارم مطلب فوق مفید واقع شود، چنانچه کم و کاستی مشاهده نمودید، اینجانب را از نظرات خود بهره مند سازید.
منبع:
مطالب
آشنایی با ساختار یک Pull Request خوب
در مطلب «نحوه‌ی مشارکت در پروژه‌های GitHub به کمک Visual Studio» با مفهوم pull request آشنا شدیم. اما ... یک pull request خوب چه خصوصیاتی دارد و فرهنگ ارسال یک PR خوب چیست؟

اخلاق مشارکت در یک پروژه‌ی سورس باز

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


بحث در مورد تغییرات پیش از ارسال PR

قبل از اینکه PR ایی را ارسال کنید، بهتر است یک issue یا ticket جدید را باز کرده و در مورد آن بحث کنید یا توضیح دهید. در این حالت ممکن است توضیحات بهتری را در مورد سازگار سازی تغییرات خود با کدهای فعلی دریافت کنید.


Pull requestها را کوچک نگه‌دارید

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


فقط یک کار را انجام دهید

شبیه به اصل تک مسئولیتی کلاس‌ها، یک PR نیز باید تنها یک کار را انجام دهد و بر روی یک موضوع خاص تمرکز داشته باشد. فرض کنید PR ایی را ارسال کرده‌اید که سه مشکل A، B و C را برطرف می‌کند. از دیدگاه مسئول اصلی پروژه، موارد A و C قابل قبول هستند؛ اما نه مورد C مطرح شده. در این حالت کل PR شما برگشت خواهد خورد. به همین جهت بهتر است بجای یک PR، سه PR مختلف و مجزا را جهت رفع مشکلات A، B و C ارسال کنید.


سازگاری تغییرات ارسالی را بررسی کنید

حداقل کاری را که پیش از ارسال PR باید انجام دهید این است که بررسی کنید آیا این تغییرات قابل Build هستند یا خیر. همچنین اگر پروژه دارای یک سری Unit tests است، حتما آن‌ها را یکبار بررسی کنید تا مطمئن شوید جای دیگری را به هم نریخته‌اید. ضمنا وجود این تست‌ها به صورت ضمنی به این معنا است که تغییرات جدید شما نیز باید به همراه تست‌های مرتبطی باشند تا پذیرفته شوند.


PR ایی را بر روی شاخه‌ی master ارسال نکنید

پس از اینکه یک fork از پروژه‌ای سورس باز را ایجاد کردید و سپس آن‌را clone نمودید تا به صورت Local بتوانید با آن کار کنید، فراموش نکنید که در همینجا باید یک branch و انشعاب جدید را جهت کار بر روی ویژگی مدنظر خود ایجاد کنید (برای مثال feature-X, fix-Y). بسیاری از پروژه‌های سورس باز به هیچ عنوان PRهای کار شده‌ی بر روی انشعاب master را قبول نمی‌کنند.


برای مطالعه بیشتر
Open Source Contribution Etiquette  
ten tips for better Pull Requests 
Getting a Pull Request Accepted 
Optimize Your Pull-request 

مطالب
آموزش MDX Query - قسمت ششم – شروع کار با دستورات MDX

امروز اولین دستورات MDX را خواهیم نوشت قبل از شروع کار فراموش نکنید موارد زیر را حتما انجام داده باشید :

  1. نصب پایگاه داده ی Adventure Work DW 2008 و همچنین نصب پایگاه داده‌ی چند بعدی  Adventure Work DW 2008  روی SSAS
  2. مطاله قسمت‌های قبلی برای آشنایی با مفاهیم پایه .

در صورتیکه پیش شرایط فوق را نداشته باشید، احتمالا در ادامه با مشکلاتی مواجه خواهید شد؛ زیرا برای آموزش MDX Query ها از پایگاه داده‌ی Adventure Work DW 2008 استفاده شده است. 

دقت داشته باشید که MDX Query ‌ها تا حدودی شبیه T/SQL  می‌باشند؛ اما مطلقا از نظر مفهومی با هم شباهت ندارند. به عبارت دیگر ما در T/SQL  با یک مدل رابطه‌ای سرو کار داریم در حالیکه در MDX ‌ها با یک پایگاه داده چند بعدی کار می‌کنیم. به بیان دیگر در پایگاه داده‌های رابطه‌ای صحبت از جداول، ردیف‌ها، ستون‌ها و ضرب دکارتی مجموعه‌ها می‌باشد، اما در پایگاه داده‌های چند بعدی در خصوص Dimension,Fact,Cube,Tuple و ... صحبت می‌کنیم. البته ماکروسافت تلاش کرده‌است تا حد زیادی Syntax ‌ها شبیه به یکدیگر باشند.

نحوه‌ی نوشتن یک Select در MDX ‌ها به صورت زیر می‌باشد :

Select
{} On Columns ,
{} On Rows
From <Cube_Name>
Where <Condition>

در ادامه با اجرای هر کوئری، توضیحات لازم در خصوص آن ارایه می‌گردد و با پیگیری این آموزش‌ها می‌توانید مفاهیم، توابع و ... را در MDX Query ‌ها بیاموزید.

برای اجرای دستورات زیر باید Microsoft SQL Server Management Studio را باز نمایید و به سرویس SSAS متصل شوید. سپس پایگاه داده‌ی Adventure Works DW 2008R2 را انتخاب نمایید و از Cubes Adventure Works را انتخاب نمایید.

حال دکمه‌ی New Query را در بالای صفحه بزنید ( Ctrl + N )  

سپس در صفحه‌ی باز شده می‌توانید Cube یا SubCube ‌های آن Cube را انتخاب کرده و کمی پایین‌تر Measure Group را خواهیم داشت و در انتها Measure ‌ها و Dimension ‌ها قرار گرفته‌اند. (در هنگام نوشتن Select می‌توان از عمل Drag&Drop برای آسان‌تر شدن نوشتن MDX Query ‌ها نیز استفاده کنید)

متاسفانه هنوز در IDE مربوط به SQL Server کلیدی برای مرتب سازی دستورات MDX وجود ندارد و البته در نرم افزار هایی مانند SQL Toll Belt هم چنین چیزی قرار داده نشده است . بنابر این توصیه می‌شود در نوشتن دستورات MDX تمام تلاش خود را بکنید تا دستوراتی مرتب و خوانا را تولید کنید.

با اجرای دستور زیر اولین کوئری خود را در پایگاه داده‌ی چند بعدی بنویسید (برای اجرا کلید F5 مانند T/SQL کار خواهد کرد.)

Select
From [Adventure Works]

شاید تعجب کنید. کوئری فاقد قسمت Projection می‌باشد! در MDX ‌ها می‌توان هیچ سطر یا ستونی را انتخاب نکرد. اما چگونه؟ و خروجی نمایش داده شده چیست؟

برای توضیح مطلب فوق باید در خصوص Default Measure کمی اطلاعات داشته باشید. در هنگام Deploy کردن پروژه در SSAS برای هر Cube یک Measure به عنوان Measure پیش فرض انتخاب شده. بنابر این در صورتیکه هیچ گونه Projection یا Where ایی اعمال نشده باشد، SQL Server به صورت پیش فرض مقدار Mesaure پیش فرض را بدون اعمال هیچ بعدی نمایش می‌دهد.

خروجی دستور بالا مشابه تصویر زیر می‌باشد. 

حال دستور زیر را اجرا می‌کنیم :

Select
From [Adventure Works]
Where [Measures].[Reseller Sales Amount]

تصویر خروجی به صورت زیر می‌باشد : 

شاید باز هم تعجب کنید. نوشتن نام یک شاخص به جای عبارت شرط؟! آیا خروجی عبارات شرطی نباید Boolean باشند؟

خیر. اگر چنین پرسش هایی در ذهن شما ایجاد شده باشد، به دلیل مقایسه‌ی MDX با T/SQL می‌باشد. در اینجا شرط Where بر روی ردیف‌های جدول مدل رابطه ای اعمال نمی‌شود و عملا بیانگر واکشی اطلاعات از مدل چند بعدی می‌باشد. با اعمال شرط فوق به SSAS اعلام کرده ایم که خروجی بر اساس شاخص [Measures].[Reseller Sales Amount] باشد. با توجه به این که شاخص انتخاب شده با شاخص پیش فرض یکی می‌باشد خروجی با حالت قبل تفاوتی نخواهد کرد.

برای درک بهتر، کوئری زیر را اجرا کنید :

Select
From [Adventure Works]
where [Measures].[Internet Sales Amount]

استفاده از این شرط سبب استفاده نشدن از شاخص پیش فرض می شود . به عبارت دیگر این کوئری دارای سرجمع مبلغ فروش اینترنتی می باشد.

دستور زیر را اجرا کنید :

Select
[Measures].[Reseller Sales Amount] on columns
From [Adventure Works]

با اعمال یک شاخص خاص در ستون ، عملا فیلترینگ انجام می شود 

استفاده از یک دایمنشن در ستون :

دستور زیر را اجرا کنید

Select
[Date].[Calendar].[Calendar Year] on columns
From [Adventure Works]

خروجی به شکل زیر خواهد بود 

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

همواره این نکته را به خاطر بسپارید که در صورت عدم ذکر نام یک Measure در کوئری ، SSAS از Measure پیش فرض استفاده می‌کند. حال کوئری فوق میزان فروش نمایندگان ( Reseller Sales Amount ) را در هر سال نمایش می‌دهد.

سوال بعدی این می‌باشد که این سال‌ها از کجا آمده اند؟ خوب برای درک بهتر این مورد می‌توانیم مانند تصویر زیر به دایمنشن Date رفته و در ساختار سلسله مراتبی ، اعضای سطح [Date].[Calendar].[Calendar Year] را مشاهده کنیم. 

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

کوئری زیر را اجرا نمایید

Select

{[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns

From [Adventure Works]

بعد از اجرا تصویر زیر را خواهید دید : 

سوال اول این می‌باشد که کاربرد {} در انتخاب دایمنشن‌ها چیست؟ در پاسخ می‌توان گفت که اگر شاخص ها یا بعد ها ، مرتبط به یک سلسله مراتب باشند آنها را در یک {} قرار می دهیم ولی اگر سلسله مراتب متفاوت باشد، یا بعد و شاخص باشند باید در () قرار بگیرند .

خوب همان طور که مشخص است در ساختار سلسله مراتبی ابتدا سال و بعد یک سطح بالا‌تر را انتخاب کرده ایم این به معنی نمایش سرجمع در سطح بالا‌تر از سال می‌باشد(سرجمع تمامی سال ها).

استفاده از دایمنشن و Measure در سطر و ستون مجرا :

کوئری زیر را اجرا نمایید

Select
{[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns,
[Product].[Product Categories].[Category] on rows
From [Adventure Works]

خروجی مشابه شکل زیر می‌باشد 

در مثال فوق از بعد‌ها در ستون و همزمان، نمایش نوع دسته بندی محصولات در ردیف‌ها استفاده شده است. به عبارت دیگر نتیجه عبارت است از فروش نماینگان فروش ( Reseller Sales Amount ) براساس هر سال به تفکیک نوع دسته بندی محصول فروخته شده.

(کسانی که چنین گزارشی را با استفاده از T/SQL نوشته اند، احتمالا از آسانی نوشتن این گزارش توسط MDX ‌ها شگفت زده شده اند.)

قراردادن فیلد سرجمع در ردیف :

برای این منظور کوئری زیر را اجرا نمایید

Select
{[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns,
{[Product].[Product Categories].[Category],[Product].[Product Categories]}on rows
From [Adventure Works]

خروجی به صورت زیر می‌باشد 

نحوه‌ی نمایش سرجمع در ردیف، مشابه نمایش سرجمع در ستون می‌باشد.

استفاده از تابع non empty  :

برای حذف ستون هایی که کاملا دارای مقدار null می‌باشند به صورت زیر عمل می‌کنیم :

Select
non empty {[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns ,
{[Product].[Product Categories].[Category],[Product].[Product Categories]} on rows
From [Adventure Works]

خروجی به صورت زیر می‌باشد:

انتخاب دو دایمنشن در سطر و ستون و مشخص نمودن یک Measure خاص برای کوئری :

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

Select
{[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns,
{[Product].[Product Categories].[Category],[Product].[Product Categories]} on rows
From [Adventure Works]
Where [Measures].[Internet Sales Amount]

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

در بالا میزان فروش اینترنتی برای دسته بندی محصولات و در سال‌های مختلف ارائه و همچنین سرجمع ستون و سطر نیز نمایش داده شده است. 

در صورتیکه بخواهیم ستون و سطرهایی را که دارای مقدار null در تمامی آن سطر یا ستون می‌باشند، حذف کنیم به صورت زیر عمل می‌کنیم:

Select
non empty {[Date].[Calendar].[Calendar Year],[Date].[Calendar]} on columns,
non empty {[Product].[Product Categories].[Category],[Product].[Product Categories]} on rows
From [Adventure Works]
Where [Measures].[Internet Sales Amount]

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

Select
[Sales Channel] on columns
From [Adventure Works]

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

Select
[Product] on columns
From [Adventure Works]

استفاده از فیلدهای یک دایمنشن که دارای سلسه مراتب می باشد نیز جایز می باشد

Select
[Product].[Category] on columns
From [Adventure Works]

Select
[Product].[Category].[all]   on columns
From [Adventure Works]
--
Select
[Product].[Category].[All] on columns
From [Adventure Works]
--
Select
[Product].[Category].[(all)] on columns
From [Adventure Works]
--
Select
[Product].[Category].[all products] on columns
From [Adventure Works]

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

در صورتی که بخواهیم از یک دایمنشن تمامی Member ‌های آن را واکشی کنیم به صورت زیر عمل خواهیم کرد

Select
{[Product].[Category].members} on columns
From [Adventure Works]

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

اگر از یک صفت واکشی اطلاعات انجام شود در سطح اعضای آن، در آن صورت دیگر سرجمع نمایش داده نمی شود و فقط جمع هر عضو در آن صفت نمایش داده می شود .

Select
[Product].[Category].[Category].members
-- dimension.hierarchy.level.members
on columns
From [Adventure Works]

اگر بخواهیم دو ستون را داشته باشیم که هر دو برای یک دایمنشن می‌باشند باید از {} استفاده کرد . دستور اول خطا خواهد داشت.

Select
[Product].[Category].[Category].members,[Product].[Category].[All Products] on columns
From [Adventure Works]

در دستور دوم با استفاده از {} خروجی نمایش داده می‌شود که عبارت است از تمامی اعضای سطح [Product].[Category].[Category]. به همراه سرجمع تمامی محصولات.

Select
{[Product].[Category].[Category].members,[Product].[Category].[All Products]} on columns
From [Adventure Works]

یک راه کوتاه‌تر برای انتخاب تمامی اعضا و سرجمع آنها

Select
{[Product].[Category].[Category],[Product].[Category]}
on columns
From [Adventure Works]

می توان از کلمات Members, All X استفاده نکرد.

انتخاب اولین دسته بندی محصول البته این ترتیب بر اساس Key Columns  در   SSAS می باشد .

Select
[Product].[Category].&[1]
on columns
From [Adventure Works]

انتخاب دقیق یک عضو در خروجی

Select
[Product].[Category].[Bikes]
on columns
From [Adventure Works]

انتخاب دو عضو از یک دایمنشن

Select
{[Product].[Category].[Bikes],[Product].[Category].[Clothing]}
on columns
From [Adventure Works]

واکشی تمامی دسته بندی محصولات بر اساس Measure پیش فرض :

Select
[Product].[Product Categories].members
on columns
From [Adventure Works]

در صورتیکه بخواهیم دو Dimension مختلف را در یک ستون یا سطر بیاوریم باید از Join استفاده کنیم. بنابر این دو دستور زیر با خطا روبرو می‌شوند

Select
[Product].[Product Categories],[Product].[Category]
on columns
From [Adventure Works]

Go

Select
{[Product].[Product Categories],[Product].[Category]}
on columns
From [Adventure Works]

تعریف Axis : به هر کدام از ستون یا سطر یک محور یا Axis گفته می‌شود.

با بررسی مثال فوق به نتایج زیر خواهیم رسید.

1. امکان استفاده از دو سلسله مراتب مختلف از یک دایمنشن در یک  Axis وجود ندارد . مگر اینکه آنها را باهمدیگر  CrossJoin کنیم .

2. امکان استفاده از دو سلسله مراتب مختلف از یک دایمنشن در دو Axis مختلف وجود دارد .

ترتیب انتخاب Axis ‌ها به صورت زیر می‌باشد:

1. Columns

2. Rows

 برای مشخص شدن موضوع کوئری زیر را اجرا کنید

Select
[Product].[Product Categories].members
on rows
From [Adventure Works]

نمی‌توانیم ردیفی را واکشی کنیم بدون اینکه ستونی برای کوئری مشخص کرده باشیم.

البته می‌توان ستون خالی ایجاد نماییم مانند مثال زیر :

Select
{} on columns,
[Product].[Product Categories].members
on rows
From [Adventure Works]

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

در مقالات بعدی به ادامه‌ی مطالب MDX Query خواهیم پرداخت.

نظرات مطالب
رسم نمودار توسط Kendo Chart
با سلام؛ در مورد خروجی PDF و یا SVG در مثال فوق، در داخل فایل jquery.ChartAjax خروجی کار نمی‌ده. لطفا راهنمایی فرمایید.
مطالب
لینک‌های هفته سوم دی

وبلاگ‌ها ، سایت‌ها و مقالات ایرانی (داخل و خارج از ایران)

ASP. Net

  • ویدیویی درباره‌ی ASP.Net 4 (بهبودهای حاصل شده در web forms از جهت کار با اسکریپت‌ها خصوصا با تاکید بر jQuery و همچنین ذکر اینکه با آمدن ASP.Net MVC ، وب فرم‌ها کهنه نشده‌ و همچنان توسعه و بهبود داده خواهند شد)، یا مقاله‌ای در این مورد

طراحی و توسعه وب

PHP

اس‌کیوال سرور

سی شارپ

عمومی دات نت

مسایل اجتماعی و انسانی برنامه نویسی

متفرقه

مطالب
بازسازی کد: جایگزینی نوع‌های داده‌های یک کلاس با زیر کلاس‌ها
یک پیاده سازی از کلاس، می‌تواند به طور ضمنی شامل دو یا چند نوع (Type) باشد. یکی از ساده‌ترین راه‌های پیاده سازی این حالت، استفاده از فیلدهایی برای نگهداری نوع اصلی داده‌ی کلاس است که اصطلاحا Type code نیز نامیده می‌شوند. به طور مثال پیاده سازی زیر را در نظر بگیرید. 

به طور مثال در کلاس بالا یک کارمند می‌تواند فروشنده یا مهندس باشد. پیاده سازی بالا این مورد را با استفاده از دو فیلد نشان داده‌است که در صورت true بودن، مقدار هریک از آن‌ها، نوع کلاس متناظر با آن خواهد بود.

مثلا اگر IsSalesman مقدار true داشته باشد، شیء ما کارمندی با نقش Salesman است و در صورتی که IsEngineer مقدار true داشته باشد ، شیء کارمند، نقش مهندس دارد. بماند که حالت‌های دیگری نیز برای مقادیر این فیلدها وجود دارند! 

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

اگر با همین فرمان کدنویسی را ادامه دهیم احتمالا با کلاسی روبرو خواهیم شد که پر است از گذاره‌های if else ، switch و یا مواردی از این دست؛ که ابدا شرایط دلپذیری برای دوستانی که قصد نگهداری از کد ما را دارند، نیست! 

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

مراحل انجام این بازسازی کد  

  1. اگر type کد درونی کلاس از طریق سازنده به کلاس ارسال شده است، این سازنده را با یک متد سازنده (Factory method) جایگزین کنید. 
  2. به ازای هر مقدار از type کدهای درونی کلاس، یک زیر کلاس جدید بسازید. 
  3. تمامی استفاده‌ها از type کدهای درونی کلاس را بازسازی کرده و به کلاس‌های مربوط به خود منتقل کنید (احتمالا تمامی پیاده سازی‌هایی که if else یا switch ای بر روی مقدار type کدها دارند).
  4. از کلاس پایه، type کد را حذف کنید. 
  5. در صورت وجود تمامی استفاده‌ها از سازنده، کلاس اولیه را به استفاده از متد سازنده تغییر دهید. 
  6. کد را کامپایل و تست نمایید.
مطالب
آشنایی با CLR: قسمت نهم
net framework. شامل Framework Class Library یا به اختصار FCL است. FCL مجموعه‌ای از dll اسمبلی‌هایی است که صدها و هزاران نوع در آن تعریف شده‌اند و هر نوع تعدادی کار انجام می‌دهد. همچنین مایکروسافت کتابخانه‌های اضافه‌تری را چون azure و Directx نیز ارائه کرده است که باز هر کدام شامل نوع‌های زیادی می‌شوند. این کتابخانه به طور شگفت آوری باعث سرعت و راحتی توسعه دهندگان در زمینه فناوری‌های مایکروسافت گشته است.

تعدادی از فناوری‌هایی که توسط این کتابخانه پشتیبانی می‌شوند در زیر آمده است:

Web Service: این فناوری اجازه‌ی ارسال و دریافت پیام‌های تحت شبکه را به خصوص بر روی اینترنت، فراهم می‌کند و باعث ارتباط جامع‌تر بین برنامه‌ها و فناوری‌های مختلف می‌گردد. در انواع جدیدتر WCF و Web Api نیز به بازار ارائه شده‌اند.

webform و MVC : فناوری‌های تحت وب که باعث سهولت در ساخت وب سایت‌ها می‌شوند که وب فرم رفته رفته به سمت منسوخ شدن پیش می‌رود و در صورتی که قصد دارید طراحی وب را آغاز کنید توصیه میکنم از همان اول به سمت MVC بروید.

Rich Windows GUI Application : برای سهولت در ایجاد برنامه‌های تحت وب حالا چه با فناوری WPF یا فناوری قدیمی و البته منسوخ شده Windows Form.
Windows Console Application: برای ایجاد برنامه‌های ساده و بدون رابط گرافیکی.
Windows Services: شما می‌توانید یک یا چند سرویس تحت ویندوز را که توسط Service Control Manager یا به اختصار SCM کنترل می‌شوند، تولید کنید.
Database stored Procedure: نوشتن stored procedure بر روی دیتابیس‌هایی چون sql server و اوراکل و ... توسط فریم ورک دات نت مهیاست.
Component Libraray: ساخت اسمبلی‌های واحدی که می‌توانند با انواع مختلفی از موارد بالا ارتباط برقرار کنند.
Portable Class Libary : این نوع پروژه‌ها شما را قادر می‌سازد تا کلاس‌هایی با قابلیت انتقال پذیری برای استفاده در سیلور لایت، ویندوز فون و ایکس باکس و فروشگاه ویندوز و ... تولید کنید.

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

در CLR مفهومی به نام Common Type System یا CTS وجود دارد که توضیح می‌دهد نوع‌ها باید چگونه تعریف شوند و چگونه باید رفتار کنند که این قوانین از آنجایی که در ریشه‌ی CLR نهفته است، بین تمامی زبان‌های دات نت مشترک می‌باشد. تعدادی از مشخصات این CTS در زیر آورده شده است ولی در آینده بررسی بیشتری روی آنان خواهیم داشت:

  • فیلد
  • متد
  • پراپرتی
  • رویدادها

CTS همچنین شامل قوانین زیادی در مورد وضعیت کپسوله سازی برای اعضای یک نوع دارد:

  • private
  • public
  • Family یا در زبان‌هایی مثل سی ++ و سی شارپ با نام protected شناخته می‌شود.
  • family and assembly: این هم مثل بالایی است ولی کلاس مشتق شده باید در همان اسمبلی باشد. در زبا‌ن‌هایی چون سی شارپ و ویژوال بیسیک، چنین امکانی پیاده سازی نشده‌است و دسترسی به آن ممکن نیست ولی در IL Assembly چنین قابلیتی وجود دارد.
  • Assembly یا در بعضی زبان‌ها به نام internal شناخته می‌شود.
  • Family Or Assembly: که در سی شارپ با نوع Protected internal شناخته می‌شود. در این وضعیت هر عضوی در هر اسمبلی قابل ارث بری است و یک عضو فقط می‌تواند در همان اسمبلی مورد استفاده قرار بگیرد.

موارد دیگری که تحت قوانین CTS هستند مفاهیم ارث بری، متدهای مجازی، عمر اشیاء و .. است.

یکی دیگر از ویژگی‌های CTS این است که همه‌ی نوع‌ها از نوع شیء Object که در فضای نام system قرار دارد ارث بری کرده‌اند. به همین دلیل همه‌ی نوع‌ها حداقل قابلیت‌هایی را که یک نوع object ارئه میدهد، دارند که به شرح زیر هستند:

  • مقایسه‌ی دو شیء از لحاظ برابری.
  • به دست آوردن هش کد برای هر نمونه از یک شیء
  • ارائه‌ای از وضعیت شیء به صورت رشته ای
  • دریافت نوع شیء جاری
CLS
وجود COM‌ها به دلیل ایجاد اشیاء در یک زبان متفاوت بود تا با زبان دیگر ارتباط برقرار کنند. در طرف دیگر CLR هم بین زبان‌های برنامه نویسی یکپارچگی ایجاد کرده است. یکپارچگی زبان‌های برنامه نویسی علل زیادی دارند. اول اینکه رسیدن به هدف یا یک الگوریتم خاص در زبان دیگر راحت‌تر از زبان پایه پروژه است. دوم در یک کار تیمی که افراد مختلف با دانش متفاوتی حضور دارند و ممکن است زیان هر یک متفاوت باشند.
برای ایجاد این یکپارچگی، مایکروسافت سیستم CLS یا Common Language Specification را راه اندازی کرد. این سیستم برای تولیدکنندگان کامپایلرها جزئیاتی را تعریف می‌کند که کامپایلر آن‌ها را باید با حداقل ویژگی‌های تعریف شده‌ی CLR، پشتیبانی کند.


CLR/CTS مجموعه‌ای از ویژگی‌ها را شامل می‌شود و گفتیم که هر زبانی بسیاری از این ویژگی‌ها را پشتیبانی می‌کند ولی نه کامل. به عنوان مثال برنامه نویسی که قصد کرده از IL Assembly استفاده کند، قادر است از تمامی این ویژگی‌هایی که CLR/CTS ارائه می‌دهند، استفاده کند ولی تعدادی دیگر از زبان‌ها مثل سی شارپ و فورترن و ویژوال بیسیک تنها بخشی از آن را استفاده می‌کنند و CLS حداقل ویژگی که بین همه این زبان‌ها مشترک است را ارائه می‌کند.
شکل زیر را نگاه کنید:

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

به کد زیر دقت کنید. تعدادی از کدها سازگاری کامل با CLS دارند که به آن‌ها CLS Compliant گویند و تعدادی از آن‌ها non-CLS-Compliant هستند یعنی با CLS سازگاری ندارند ولی استفاده از خاصیت [(assembly: CLSCompliant(true]  باعث می‌شود که تا کامپایلر از پشتیبانی و سازگاری این کدها اطمینان کسب کند و در صورت وجود، از اجرای آن جلوگیری کند. با کمپایل کد زیر دو اخطار به ما میرسد.
using System;

// Tell compiler to check for CLS compliance
[assembly: CLSCompliant(true)]

namespace SomeLibrary {

// Warnings appear because the class is public
public sealed class SomeLibraryType {

// Warning: Return type of 'SomeLibrary.SomeLibraryType.Abc()'
// is not CLS­compliant
public UInt32 Abc() { return 0; }

// Warning: Identifier 'SomeLibrary.SomeLibraryType.abc()'
// differing only in case is not CLS­compliant
public void abc() { }

// No warning: this method is private
private UInt32 ABC() { return 0; }
}
}

اولین اخطار اینکه یکی از متدها یک عدد صحیح بدون علامت unsigned integer را بر می‌گرداند که همه‌ی زبان‌ها آن را پشتیبانی نمی‌کنند و خاص بعضی از زبان هاست.
دومین اخطار اینکه دو متد یکسان وجود دارند که در حروف بزرگ و کوچک تفاوت دارند. ولی زبان هایی چون ویژوال بیسیک نمی‌توانند تفاوتی بین دو متد abc و ABC بیابند.

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

سازگاری با کدهای مدیریت نشده
در بالا در مورد یکپارچگی و سازگاری کدهای مدیریت شده توسط CLS صحبت کردیم ولی در مورد ارتباط با کدهای مدیریت نشده چطور؟
مایکروسافت موقعیکه CLR را ارئه کرد، متوجه این قضیه بود که بسیاری از شرکت‌ها توانایی اینکه کدهای خودشون را مجددا طراحی و پیاده سازی کنند، ندارند و خوب، سورس‌های مدیریت نشده‌ی زیادی هم موجود هست که توسعه دهندگان علاقه زیادی به استفاده از آن‌ها دارند. در نتیجه مایکروسافت طرحی را ریخت که CLR هر دو قسمت کدهای مدیریت شده و نشده را پشتیبانی کند. دو نمونه از این پشتیبانی را در زیر بیان می‌کنیم:
یک. کدهای مدیریت شده می‌توانند توابع مدیریت شده را در قالب یک dll صدا زده و از آن‌ها استفاده کنند.
دو. کدهای مدیریت شده می‌توانند از کامپوننت‌های COM استفاده کنند: بسیاری از شرکت‌ها از قبل بسیاری از کامپوننت‌های COM را ایجاد کرده بودند که کدهای مدیریت شده با راحتی با آن‌ها ارتباط برقرار می‌کنند. ولی اگر دوست دارید روی آن‌ها کنترل بیشتری داشته باشید و آن کدها را به معادل CLR تبدیل کنید؛ میتوانید از ابزار کمکی که مایکروسافت همراه فریم ورک دات نت ارائه کرده است استفاده کنید. نام این ابزار TLBIMP.exe می‌باشد که از Type Library Importer گرفته شده است.

سه. اگر کدهای مدیریت نشده‌ی زیادتری دارید شاید راحت‌تر باشد که برعکس کار کنید و کدهای مدیریت شده را در در یک برنامه‌ی مدیریت نشده اجرا کنید. این کدها می‌توانند برای مثال به یک Activex یا shell Extension تبدیل شده و مورد استفاده قرار گیرند. ابزارهای TLBEXP .exe و RegAsm .exe برای این منظور به همراه فریم ورک دات نت عرضه شده اند.
سورس کد Type Library Importer را میتوانید در کدپلکس بیابید.
در ویندوز 8 به بعد مایکروسافت API جدید را تحت عنوان WinsowsRuntime یا winRT ارائه کرده است . این api یک سیستم داخلی را  از طریق کامپوننت‌های com ایجاد کرده و به جای استفاده از فایل‌های کتابخانه‌ای، کامپوننت‌ها api هایشان را از طریق متادیتاهایی بر اساس استاندارد ECMA که توسط تیم دات نت طراحی شده است معرفی می‌کنند.
زیبایی این روش اینست که کد نوشته شده در زبان‌های دات نت  می‌تواند به طور مداوم با api‌های winrt ارتباط برقرار کند. یعنی همه‌ی کارها توسط CLR انجام می‌گیرد بدون اینکه لازم باشد از ابزار اضافی استفاده کنید. در آینده در مورد winRT بیشتر صحبت می‌کنیم.
 
سخن پایانی: ممنون از دوستان عزیز بابت پیگیری مطالب تا بدینجا. تا این قسمت فصل اول کتاب با عنوان اصول اولیه CLR بخش اول مدل اجرای CLR به پایان رسید.
ادامه‌ی مطالب بعد از تکمیل هر بخش در دسترس دوستان قرار خواهد گرفت.
نظرات اشتراک‌ها
معرفی کتابخانه‌ی DNTPersianUtils.Core
- متد ToGregorianDateTime که برای تبدیل رشته‌ی تاریخ شمسی به میلادی کاربرد دارد، خروجی ?DateTime دارد (اگر رشته قابل تبدیل نباشد، نال دریافت می‌کنید). 
- علامت ? در این خطا یعنی استفاده از nullable type و انتساب آن به نمونه‌ی غیرنال‌پذیر. بنابراین dt.Value را باید استفاده کنید که DateTime باشد.
- مشکلی نیست. در کل مشکلات را با ذکر جزئیات در اینجا گزارش کنید.
- منهای بحث گروه بندی اطلاعات بر اساس ماه‌های شمسی، در مورد دیگری نیاز به تاریخ رشته‌ای شمسی پیدا نمی‌کنید و اگر با ORMها کار می‌کنید بهتر است از DateTimeOffset استفاده کنید.
اشتراک‌ها
برنامه مترجم فایل زبان فروشگاه NopCommerce
در راستای پروژه قبلی (برنامه مترجم گوگل به زبان #C )  که معرفی کردم، این برنامه با گرفتن فایل زبان نوپ کامرس، اون رو به هر زبانی که بخواهید ترجمه می‌کنه (به کمک گوگل) و فایل آماده استفاده را به شما تحویل می‌دهد.
همان طور که در متن هم توضیح دادم، بنده برنامه نویس ویندوز نیستم و این تخصص من نیست. از طرفی چون این برنامه قرار هست در سایت نوپ کامرس معرفی بشود، بهتر هست که از لحاظ ساختاری وضعیت مناسبی داشته باشد، ممنون می‌شم از دوستانی که تخصصشان برنامه‌های ویندوزی هست در بهبود این برنامه به من کمک کنند.
موفق باشید
برنامه مترجم فایل زبان فروشگاه NopCommerce
نظرات مطالب
ASP.NET MVC #1
- در نظرات مطلب «PHP سریعتر از ASP.NET! افسانه یا واقعیت؟ » در مورد علت تاخیر اولیه نمایش سایت‌های ASP.NET بحث شده. (چند مرحله‌ای بودن کامپایل کدهای دات نت و زمان بارگذاری اولیه برنامه در یک پروسه وب؛ بعد از این گذر اولیه الزامی، با سرعت خوبی مواجه خواهید بود)
- ضمنا بحث MVC، بحث سرعت نیست. این‌ها مسایل حاشیه‌ای هستند. اینجا در مورد یک طرز تفکر دیگر، در مورد بکارگیری الگوها، تهیه برنامه‌هایی با قابلیت آزمون پذیری بهتر، تمیزتر و اصولی کار کردن بیشتر بحث می‌شود و نه مسابقه‌ی سرعت.