اشتراک‌ها
کتاب رایگان Java Succinctly Part 1

Java is a high-level, cross-platform, object-oriented programming language that allows applications to be written once and run on a multitude of different devices. Java applications are ubiquitous, and the language is consistently ranked as one of the most popular and dominant in the world. Christopher Rose’s Java Succinctly Part 1 describes the foundations of Java–from printing a line of text to the console, to inheritance hierarchies in object-oriented programming. The e-book covers practical aspects of programming, such as debugging and using an IDE, as well as the core mechanics of the language.

Table of Contents
  1. Introduction
  2. Getting Started
  3. Writing Output
  4. Reading Input
  5. Data Types and Variables
  6. Operators and Expressions
  7. Control Structures
  8. Object-Oriented Programming
  9. Example Programs and Conclusion 
کتاب رایگان Java Succinctly Part 1
مطالب
ایجاد Drop Down List های آبشاری در Angular
تاکنون دو مطلب مشابه «ساخت DropDownList‌های مرتبط به کمک jQuery Ajax در MVC» و «ایجاد Drop Down List‌های آبشاری توسط Kendo UI» را در مورد ساخت Cascading Drop-down Lists در این سایت مطالعه کرده‌اید. در اینجا قصد داریم چنین قابلیتی را توسط Angular پیاده سازی کنیم (بدون استفاده از هیچ کتابخانه‌ی ثالث دیگری).



مدل‌های سمت سرور برنامه

در این مطلب قصد داریم لیست گروه‌ها را به همراه محصولات مرتبط با آن‌ها، توسط دو drop down list نمایش دهیم:
public class Category
{
    public int CategoryId { set; get; }
    public string CategoryName { set; get; }

    [JsonIgnore]
    public IList<Product> Products { set; get; }
}


public class Product
{
    public int ProductId { set; get; }
    public string ProductName { set; get; }
}
از ویژگی JsonIgnore جهت عدم درج لیست محصولات، در خروجی JSON نهایی تولیدی گروه‌ها، استفاده شده‌است (و کتابخانه‌ی JSON.NET، کتابخانه‌ی پیش فرض کار با JSON در ASP.NET Core است).


منبع داده JSON سمت سرور

پس از مشخص شدن مدل‌های برنامه، اکنون توسط دو اکشن متد، لیست گروه‌ها و همچنین لیست محصولات یک گروه خاص را با فرمت JSON بازگشت می‌دهیم:
namespace AngularTemplateDrivenFormsLab.Controllers
{
    [Route("api/[controller]")]
    public class ProductController : Controller
    {
        [HttpGet("[action]")]
        public async Task<IActionResult> GetCategories()
        {
            await Task.Delay(500);

            return Json(CategoriesDataSource.Items);
        }

        [HttpGet("[action]/{categoryId:int}")]
        public async Task<IActionResult> GetProducts(int categoryId)
        {
            await Task.Delay(500);

            var products = CategoriesDataSource.Items
                            .Where(category => category.CategoryId == categoryId)
                            .SelectMany(category => category.Products)
                            .ToList();
            return Json(products);
        }
    }
}
- بار اولی که صفحه بارگذاری می‌شود، توسط یک درخواست Ajax ایی، لیست گروه‌ها دریافت خواهد شد. سپس با انتخاب یک گروه، اکشن متد GetProducts جهت بازگرداندن لیست محصولات آن گروه، فراخوانی می‌گردد. کدهای کامل CategoriesDataSource در فایل پیوستی انتهای بحث قرار داده شده‌است و یک منبع ساده درون حافظه‌ای است.
- در اینجا از یک Delay نیز استفاده شده‌است تا بتوان آیکن‌های چرخند‌ه‌ی Loading سمت کاربر را در حین کار با عملیاتی زمانبر، بهتر مشاهده کرد.


 کدهای سمت کاربر برنامه

کدهای سمت کاربر این مثال در ادامه‌ی همان مطلب «فرم‌های مبتنی بر قالب‌ها در Angular - قسمت پنجم - ارسال اطلاعات به سرور» هستند که بر روی آن این دستورات فراخوانی شده‌است:
 >ng g m Product -m app.module --routing
ماژول جدیدی به نام محصولات اضافه و به app.module معرفی شده‌است. البته پس از اصلاح، ProductModule بجای ProductRoutingModule در این فایل تنظیم خواهد شد.

 >ng g c product/product-group
سپس یک کامپوننت جدید به نام ProductGroupComponent درون ماژول Product ایجاد شده‌است.

>ng g cl product/product
>ng g cl product/Category
>ng g cl product/product-group-form
در ادامه سه کلاس Product، Category و ProductGroupForm به این ماژول اضافه شده‌اند که دو مورد اول، معادل کلاس‌های مدل سمت سرور و مورد سوم، معادل فرم جدید ProductGroupComponent است:
export class ProductGroupForm {
  constructor(
    public categoryId?: number,
    public productId?: number
  ) { }
}

export class Product {
  constructor(
    public productId: number,
    public productName: string
  ) { }
}

export class Category {
  constructor(
    public categoryId: number,
    public categoryName: string
  ) { }
}

سپس سرویسی را جهت دریافت اطلاعات دراپ داون‌ها از سرور تهیه کرده‌ایم:
 >ng g s product/product-items -m product.module
با این محتوا:
import { Injectable } from "@angular/core";
import { Http, Response, Headers, RequestOptions } from "@angular/http";

import { Observable } from "rxjs/Observable";
import "rxjs/add/operator/do";
import "rxjs/add/operator/catch";
import "rxjs/add/observable/throw";
import "rxjs/add/operator/map";
import "rxjs/add/observable/of";

import { Category } from "./category";
import { Product } from "./product";

@Injectable()
export class ProductItemsService {

  private baseUrl = "api/product";

  constructor(private http: Http) { }

  private handleError(error: Response): Observable<any> {
    console.error("observable error: ", error);
    return Observable.throw(error.statusText);
  }

  getCategories(): Observable<Category[]> {
    return this.http
      .get(`${this.baseUrl}/GetCategories`)
      .map(response => response.json() || {})
      .catch(this.handleError);
  }

  getProducts(categoryId: number): Observable<Product[]> {
    return this.http
      .get(`${this.baseUrl}/GetProducts/${categoryId}`)
      .map(response => response.json() || {})
      .catch(this.handleError);
  }
}
از متد getCategories برای پر کردن اولین drop down استفاده خواهد شد و از متد دوم برای دریافت لیست محصولات متناظر با یک گروه انتخاب شده کمک می‌گیریم.

پس از این مقدمات اکنون می‌توان کدهای ProductGroupComponent را تکمیل کرد.
ابتدا در متد ngOnInit آن کار دریافت لیست آغازین گروه‌های محصولات را انجام می‌دهیم:
export class ProductGroupComponent implements OnInit {

  categories: Category[] = [];
 model = new ProductGroupForm();

  constructor(private productItemsService: ProductItemsService) { }

  ngOnInit() {
    this.productItemsService.getCategories().subscribe(
      data => {
        this.categories = data;
      },
      err => console.log("get error: ", err)
    );
  }
برای این منظور ابتدا ProductItemsService به سازنده‌ی کلاس تزریق شده‌است تا بتوان به متدهای دریافت اطلاعات از سرور دسترسی یافت. سپس در متد ngOnInit، اطلاعات دریافتی به خاصیت عمومی categories انتساب داده شده‌است.
اکنون چون این خاصیت در دسترس است، می‌توان به قالب این کامپوننت مراجعه کرده و قسمت ابتدایی فرم را تکمیل کرد:
<div class="container">
  <h3>Cascading Drop-down Lists</h3>
  <form #form="ngForm" (submit)="submitForm(form)" novalidate>
    <div class="form-group">
      <label class="control-label">Category</label>
      <span class="glyphicon glyphicon-refresh glyphicon-spin spinner" *ngIf="categories.length == 0"></span>
      <select class="form-control" name="categoryCtrl" #categoryCtrl (change)="fetchProducts(categoryCtrl.value)"
        [(ngModel)]="model.categoryId">
        <option value="undefined">Select a Category...</option>
        <option *ngFor="let category of categories" value="{{category.categoryId}}">
          {{ category.categoryName }}
        </option>
      </select>
    </div>
- در اینجا اولین ngIf بکار گرفته شده، طول آرایه‌ی categories (همان خاصیت عمومی معرفی شده‌ی در کامپوننت) را بررسی می‌کند. اگر این آرایه خالی باشد، یک آیکن چرخنده را نمایش می‌دهد.
- سپس ngModel به خاصیت categoryId وهله‌ای از کلاس ProductGroupForm که مدل معادل فرم است، متصل شده‌است.
- همچنین با اتصال به رخداد change، مقدار Id عضو انتخابی به متد fetchProducts ارسال می‌شود. دسترسی به این Id از طریق یک template reference variable به نام categoryCtrl# انجام شده‌است.
- در آخر، ngFor تعریف شده به ازای هر عضو آرایه‌ی categories، یکبار تگ option را تکرار می‌کند و در هربار تکرار، مقدار ویژگی value را به categoryId تنظیم می‌کند و برچسب نمایشی آن‌را از categoryName دریافت خواهد کرد.

بنابراین مرحله‌ی بعدی تکمیل این drop down آبشاری، واکنش نشان دادن به رخ‌داد change و تکمیل متد fetchProducts است:
  products: Product[] = [];
  isLoadingProducts = false;

  fetchProducts(categoryId?: number) {
    console.log(categoryId);

    this.products = [];

    if (categoryId === undefined || categoryId.toString() === "undefined") {
      return;
    }

    this.isLoadingProducts = true;
    this.productItemsService.getProducts(categoryId).subscribe(
      data => {
        this.products = data;
        this.isLoadingProducts = false;
      },
      err => {
        console.log("get error: ", err);
        this.isLoadingProducts = false;
      }
    );
  }
- در ابتدای متد fetchProducts، آرایه‌ی خاصیت عمومی products که به drop down دوم متصل خواهد شد، خالی می‌شود تا تداخلی با اطلاعات قبلی آن حاصل نشود.
- سپس بررسی می‌کنیم که آیا categoryId دریافتی undefined است یا خیر؟ این مساله دو علت دارد:
الف) اولین عضو drop down انتخاب محصولات را با مقدار undefined مشخص کرده‌ایم:
 <option value="undefined">Select a Category...</option>
ب) علت اینجا است که چون ngModel به model.categoryId متصل شده‌است و در این مدل، پارامتر و همچنین خاصیت عمومی categoryId از نوع optional است و با ؟ مشخص شده‌است:
 public categoryId?: number
به همین جهت زمانیکه مدل را به این صورت تعریف می‌کنیم:
 model = new ProductGroupForm();
مقدار categoryId همان undefined جاوا اسکریپت خواهد بود.

- پس از آن همانند قسمت قبل، این categoryId را به سرور ارسال کرده و سپس اطلاعات متناظری را دریافت و به خاصیت عمومی products  نسبت داده‌ایم. همچنین از یک خاصیت عمومی دیگر به نام isLoadingProducts نیز استفاده شده‌است تا مشخص شود چه زمانی کار دریافت اطلاعات از سرور خاتمه پیدا می‌کند. از آن برای نمایش یک آیکن چرخنده‌ی دیگر استفاده می‌کنیم:
    <div class="form-group">
      <label class="control-label">Product</label>
      <span class="glyphicon glyphicon-refresh glyphicon-spin spinner" *ngIf="isLoadingProducts"></span>
      <select class="form-control" name="productCtrl" [(ngModel)]="model.productId">
        <option value="undefined">Select a Product...</option>
        <option *ngFor="let product of products" value="{{product.productId}}">
          {{ product.productName }}
        </option>
      </select>
    </div>
به این ترتیب drop down دوم بر اساس مقدار خاصیت عمومی products تشکیل می‌شود. اگر مقدار isLoadingProducts مساوی true باشد، یک spinner که کدهای css آن‌را در فایل src\styles.css به نحو ذیل تعریف کرده‌ایم، نمایان می‌شود و برعکس. همچنین ngFor به ازای هر عضو آرایه‌ی products یکبار تگ option را تکرار خواهد کرد.
/* Spinner */
.spinner {
  font-size:15px;
  z-index:10
}

.glyphicon-spin {
    -webkit-animation: spin 1000ms infinite linear;
    animation: spin 1000ms infinite linear;
}
@-webkit-keyframes spin {
    0% {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
    }
    100% {
        -webkit-transform: rotate(359deg);
        transform: rotate(359deg);
    }
}
@keyframes spin {
    0% {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
    }
    100% {
        -webkit-transform: rotate(359deg);
        transform: rotate(359deg);
    }
}

کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: angular-template-driven-forms-lab-06.zip
برای اجرای آن فرض بر این است که پیشتر Angular CLI را نصب کرده‌اید. سپس به ریشه‌ی پروژه وارد شده و دو پنجره‌ی کنسول مجزا را باز کنید. در اولی دستورات
>npm install
>ng build --watch
و در دومی دستورات ذیل را اجرا کنید:
>dotnet restore
>dotnet watch run
اکنون می‌توانید برنامه را در آدرس http://localhost:5000 مشاهده و اجرا کنید.
مطالب
تعریف انبار داده Data Warehouse
در این مقاله در ادامه‌ی مطلبی که تحت عنوان «آموزش مفاهیم Data Warehouse» توسط آقای شاه قلی منتشر شده بود، به بررسی بیشتر مفهوم انبار داده ( Data Warehouse ) پرداخته می‌شود.

مقدمه
در سازمان ها، داده‌ها و اطلاعات معمولاً به دو شکل در سیستم‌ها پیاده سازی می‌گردد:
• سیستم‌های عملیاتی  OLTP:
این سیستم‌ها باعث می‌گردند تا چرخ کسب و کار بگردد. وجود این سیستم‌ها سبب می‌شود تا داده‌های مربوط به کسب و کار، به بانک اطلاعاتی وارد شوند. این سیستم‌ها عموماً:
o به دلیل کوتاهی عملیات دارای سرعت قابل توجهی می‌باشند.
o محیطی جهت ورود داده‌ها می‌باشند.
o معمولاً اپراتورها، استفاده کننده‌های آن هستند.
• سیستم‌های اطلاعاتی OLAP ، DW/BI، DSS :
این سیستم‌ها باعث می‌گردند تا چرخش کسب و کار را بنگرید. فلسفه بکارگیری این سیستم‌ها در سازمان این است که اطلاعات مورد نیاز مدیران، از درون داده‌های سیستم‌های عملیاتی موجود، استخراج گردد. این سیستم‌ها عموماً:
o به دلیل آنالیز حجم انبوهی از داده ها، معمولاً کندتر از سیستم‌های عملیاتی می‌باشند.
o محیطی جهت تولید گزارشات تحلیلی و آماری می‌باشند.
o معمولاً مدیران و تصمیم گیرندگان سازمان ها، استفاده کنندگان آن می‌باشند.
سیستم‌های عملیاتی در جامعه ما سابقه بیشتری داشته و متخصصین فناوری اطلاعات عموماً با طراحی و تولید چنین سیستم هایی آشنایی کافی دارند. متاسفانه جایگاه سیستم‌های اطلاعاتی در جامعه ما کمتر شناخته شده و متخصصین فناوری اطلاعات بندرت با مفاهیم و نحوه پیاده سازی آن آشنایی دارند.
این نکته حائز اهمیت است که سیستم‌های اطلاعاتی یک سیستم یا محصول نیستند که بتوان آنها را خریداری کرد. بلکه یک راهبرد (Solution, Approach) هستند و در حقیقت هر راهبردی مربوط به یک نوع کسب و کار (Business) و یا سازمان می‌باشد و نمی‌توان فرمول واحدی را برای حتی سازمان‌های مشابه، ارائه نمود.

گارتنر در ابتدای سال 2011 گزارشی را منتشر کرده که نشان میدهد بازار BI با 9.7 % رشد، ارزشی بالغ بر 10.8 بیلیون دلار داشته، ولی متاسفانه پروژه‌های آن به طور متوسط با 75% شکست مواجه شده است. در حالیکه 4 سال پیش، این رقم حدود 50% بود. این موسسه BI را پنجمین اولویت مدیران IT ذکر کرده است.

مفاهیم و مباحث مربوط به Data Warehouse به اواسط دهه 1980 برمی گردد، به زمانی که IBM تحقیقاتی را در این زمینه شروع کرد و نتیجه آنرا «Information Warehouse» نامید و هنوز هم در برخی منابع از این واژه بجای Data Warehouse استفاده می‌شود. از این پس برای راحتی از اختصار DW بجای Data Warehouse استفاده می‌شود. انبارهای داده جهت رفع نیاز رو به رشد مدیریت داده‌ها و اطلاعات سازمانی که توسط پایگاه‌های داده سیستم‌های عملیاتی غیر ممکن بود، ساخته شدند.

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

Bill Inmon:
او را پدر DW می‌نامند، از دیدگاه او DW هسته مرکزی چیزی است که او آنرا CIF اختصار (Corporate Information Factory) می‌نامد، که پایه و اساس BI بر مبنای آن قرار دارد. وی از طرفداران Top-Down Design می‌باشد که معتقد است در زمان طراحی باید با دیدی سازمانی، CIF را مدل سازی، ولی بصورت دپارتمانی پیاده سازی کرد (Think Globally, Implement Locally). در این نوع طراحی از DW به Data Mart خواهیم رسید.

Ralph Kimball Ph.D:
به نظر وی DW چیزی نیست جز یک کپی از داده‌های عملیاتی که به طرز خاصی برای گزارشات و تحلیل‌های آماری، آماده و ساختمند شده است. به بیان دیگر DW سیستمی است جهت استخراج، پالایش، تطبیق و تحویل اطلاعات منابع داده ای به یک بانک اطلاعاتی Dimensional و اجرای Query و گزارشات آماری و تحلیلی برای اهداف تصمیم گیری و استراتژیک سازمان.
وی معرفی کننده یکی از اساسی‌ترین مفاهیم طراحی یعنی Dimensional Modeling است؛ ماحصل چنین ایده ای، اساس شکل گیری مدلی است که امروزه کارشناسان آنرا به نام Cube می‌شناسند. وی از طرفداران Bottom-Up Design است که در این نگرش از Data Mart به DW می‌رسیم. این روش به نظر عملی‌تر از روشی می‌باشد که به یکباره DW جامع و کامل برای اهداف سازمانی طراحی و پیاده سازی گردد.

تعریف انبار داده:
W.H.Inmon پدر DW آنرا چنین تعریف می‌کند:
The Data Warehouse is a collection of Integrated, Subject-Oriented databases designed to support the DSS function, where each unit of data is Non-Volatile and relevant to some moment in Time
از تعریف فوق دو مورد دیگر نیز به طور ضمنی استنباط می‌شود:
o انبار داده به طور فیزیکی، کاملاً جدا از سایر سیستم‌های عملیاتی است.
o داده‌های DW مجموعه ای Aggregated و Atomic از داده‌های تراکنش‌های سیستم‌های عملیاتی است که سوای کاربرد آنها در سیستم‌های عملیاتی، برای مقاصد مدیریتی نیز استفاده خواهد شد.

به بیان دیگر DW راهبردی است که دسترسی آسان به اطلاعات درست (Right Information)، در زمانی درست (Right Time) ، به کاربران درست (Right Users)، را فراهم می‌آورد تا «تصمیم گیری سازمانی» قابل انجام باشد. DW صرفاً یک محصول نرم افزاری و یا سخت افزاری نیست که بتوان آنرا خریداری نمود بلکه فراتر از آن و در حقیقت یک محیط پردازشی می‌باشد که کاربران می‌توانند از درون آن اطلاعات مورد نیاز خود را بیابند.
DW اطلاعات خود را از سایر بانک‌های اطلاعاتی از نوع OLTP و یا سایر DW‌های لایه پایین‌تر و به صورت دسته ای (Batch) و یا انبوه (Bulk Loading) جمع آوری می‌کند. یک DW به صورت سنتی باید شامل داده‌های Historic سازمان باشد و می‌توان اینگونه بیان نمود که در DW هرچه داده‌های قدیمی‌تری موجود باشد، اعتبار تحلیل‌های آماری سیستم افزایش خواهد یافت.

داده‌های سیستم عملیاتی را نمی‌توان بلافاصله درون بانک اطلاعاتی DW لود نمود، چنین داده هایی باید آماده سازی، پالایش و همگون گردند تا شرایط لود در DW را داشته باشند. حداقل کاری که انتظار داریم یک DW در مورد داده‌ها برای ما برآورده سازد شامل موارد زیر است:
o استخراج داده‌ها از منابع مختلف (مبدإ)
o تبدیل داده‌ها به فرمتی یکسان
o لود داده‌ها به جداول مربوطه (مقصد)
با هر با اجرای پروسه فوق یکی از سه مورد زیر، بسته به نیاز طراحی و محدودیت‌های تکنولوژی رخ خواهد داد:
o تمام داده‌ها در DW با داده‌های جدید جایگزین خواهند گردید(Full Load, Initial Load, Full Refresh).
o داده‌های جدید به داده‌های موجود اضافه خواهند گردید (Incremental Load (Inserted data.
o نسخه جدیدی از داده‌های کنونی به سیستم اضافه خواهند گردید (Incremental Load (Updated data.


ویژگی‌های داده‌های درون DW
داده‌های DW از نگاه Inmon دارای 4 ویژگی اصلی زیر هستند:
o فقط خواندنی (Non-Volatile):
هیچ رکوردی و یا داده ای Update نخواهد شد و صرفاً رکوردهایی که محتوای مقادیر جدید داده‌ها هستند، به سیستم اضافه خواهند شد.
o موضوع گرا (Subject-Oriented):
منظور از «موضوع» پایه‌های اساسی یک کسب و کار هستند، به شکلی که با حذف یکی از این پایه ها، شاید ماهیت آن کسب و کار از ریشه دگرگون شود. برای مثال موضوعاتی چون «مشتری» و یا «بیمه نامه» برای شرکت‌های بیمه.
o جامع (Integrated):
باید تمامی کدهایی که در سیستم‌های عملیاتی وجود دارند و معانی یکسانی دارند، برای مثال کد جنسیت، در DW به یک روش ذخیره و نمایش داده شوند.
o زمانگرا (Time Variant):
هر رکورد باید حاوی فیلد و یا کلیدی باشد که نمایانگر این باشد که این رکورد در چه زمانی ایجاد، استخراج و ذخیره شده است. از آنجا که داده‌های درون سیستم‌های عملیاتی آخرین و به روز‌ترین داده هر سیستم میباشد، نیازی به وجود چنین عنصری در سیستم‌های OLTP احساس نمی‌گردد، ولی چون در DW تمام داده‌های نسخ قدیمی داده‌های سیستم‌های عملیاتی موجود می‌باشد، باید حتماً مشخص گردد که هر داده ای در سیستم‌های عملیاتی در چه زمانی، چه مقادیری داشته است. این عنصر زمانی کمک می‌کند تا بتوانیم:
o گذشته را آنالیز کنیم.
o اطلاعات مربوط به حال حاضر را بدست آوریم.
o آینده را پیش بینی کنیم.

منبع: کتاب آقای خشایار جام سحر با عنوان بانک داده تجمیعی
Comparison  Kimball vs. Inmon

Inmon
Continuous & Discrete Dimension Management
Define data management via dates in your data
Continuous time  
  When is a record active
Start and end dates
Discrete time  
 A point in time
  Snapshot
 
Kimball
Slowly Changing Dimension Management
Define data management via versioning
Type I  
  Change record as required
  No History
Type II  
  Manage all changes
 History is recorded
Type III  
  Some history is parallel
  Limit to defined history


Kimball 
Inmon 
Business-Process-Oriented
Stresses Dimensional Model, Not E-R
Subject-Oriented
Integrated
Non-Volatile
Time-Variant
Bottom-Up and Evolutionary 
Top-Down 
Integration Achieved via Conformed Dimensions 
Integration Achieved via an Assumed Enterprise Data Model 
Star Schemas Enforce Query Semantics 
Characterizes Data marts as Aggregates 
Kimball
Inmon

Bottom-up
Top-down
Overall approach
Data marts model a business process;enterprise is achieved with conformed dims
Enterprise-wide DW feeds departmental DBs
Architectural structure
Fairly simple
Quite complex
Complexity of method
Process oriented
Subject or data driven
Data orientation
Dimensional modeling; departs from traditional relational modeling
Traditional  ERDs and DIS
Tools
High
Low
End user accessibility
Slowly Changing
Continuous & Discrete
Timeframe
Dimension keys
Timestamps
Methods
نظرات مطالب
امن سازی درخواست‌های ای‌جکسی برنامه‌های ASP.NET MVC 5.x در مقابل حملات CSRF
ممنونم. مطلب رو خوندم. ولی باز برام سواله، در کد شما postId در کجای تابع addToken  مقدارش ست میشه. آیا نباید به این شکل باشه:
function addToken(data) {
   data.__RequestVerificationToken = $("input[name=__RequestVerificationToken]").val();
   data.postId=postId;
   return data;
}
نظرات مطالب
یک دست سازی ی و ک در برنامه‌های Entity framework 6
دلیل تغییراتی که در رشته رو میدید متوجه نشدم! استفاده از trim و بازگردادن رشته خالی
به نظرم اینطوری بهتره:
public static string ApplyCorrectYeKe(this string data)
{
return string.IsNullOrWhiteSpace(data)
? data
: data.Replace(ArabicYeChar, PersianYeChar).Replace(ArabicKeChar, PersianKeChar);
}
نظرات مطالب
ASP.NET MVC #13
میخواستم بدون آیا استفاده از Data Annotation‌ها توی همون کلاسای Data Access Layer مثلاً وقتی از Code First استفاده میکنیم کار درستی هست؟
یا بهتره یه کلاس دیگه (ViewModel) ساخت و توی اون Data Annotation‌ها رو تعریف کرد و بعد با Auto Mapper به هم Map کرد؟ 
مطالب
کتابخانه‌ی انواع و اقسام مدل‌های داده‌ای

سایت databaseanswers.org قسمتی را دارد تحت عنوان Data models که طراحی دیتابیس بیش از 600 سیستم را جمع آوری کرده است.
از data model سیستم مدیریت ارتباطات



تا data model یک باغ وحش





اشتراک‌ها
معماری Vertical Slice بهتر است از کار با لایه‌ها!

Vertical Slice Architecture, not Layers! 

Why Vertical Slice Architecture? Nobody wants to deal with a system that is hard to change and easy to introduce bugs because it's a spaghetti code mess of various technical concerns. Clean Architecture is popular because it separates concerns into many different layers. But why are we organizing code by layers? Does adding a new feature require you to modify files across multiple projects in your UI, business, and data access layers? Vertical Slice Architecture is about how you organize code and focus on features instead of technical layers will make your system easier to change. 

معماری Vertical Slice بهتر است از کار با لایه‌ها!
بازخوردهای پروژه‌ها
تولید پویای رشته 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 تولید شده؟ یا نحوه ارسال پارامتر؟
مطالب
آغاز کار با الکترون
در مقاله «آشنایی با الکترون» با نحوه نصب و راه اندازی آن آشنا شدیم. در این مقاله با تعدادی اصطلاح، آشنا شده و یک برنامه ساده را برای نوشتن و خواندن فایل‌ها، می‌نویسیم.
فرآیندها (Processes) در الکترون به دو بخش تقسیم می‌شوند:

یک. فرآیند اصلی (Main Process) که همان فایل جاوااسکریپتی است و توسط main، در فایل package.json مشخص شده‌است .فرآیند اصلی تنها فرآیندی است که قابلیت دسترسی به امکانات گرافیکی سیستم عامل را از قبیل نوتیفیکشن ها، دیالوگ‌ها ،Tray و ... دارد. فرآیند اصلی می‌تواند با استفاده از شیء BrowserWindow که در قسمت قبلی کاربرد آن را مشاهده کردیم، render process را ایجاد کند. با هر بار ایجاد یک نمونه از این شیء، یک Render Process ایجاد می‌شود.

دو. فرآیند رندر (Render Process): از آنجا که الکترون از کرومیوم استفاده می‌کند و کرومیوم شامل معماری چند پردازشی است، هر صفحه‌ی وب می‌تواند پردازش خود را داشته باشد که به آن Render Process می‌گویند. به طور معمول در مرورگرها، صفحات وب در محیطی به نام SandBox اجرا می‌شوندکه اجازه دسترسی به منابع بومی را ندارند. ولی از آنجا که الکترون می‌تواند از Node.js استفاده کند، قابلیت دسترسی به تعاملات سطح پایین سیستم عامل را نیز داراست.

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


در ابتدا قصد داریم یک منو برای برنامه‌ی خود درست کنیم. برای ساخت منو، راه‌های متفاوتی وجود دارند که فعلا ما راه استفاده از template را بر می‌گزینیم که به صورت یک آرایه نوشته می‌شود. کدهای زیر را در فایل index.js یا هر اسمی که برای آن انتخاب کرده‌اید بنویسید:
const electron = require('electron');
const {app,dialog,BrowserWindow,Menu,shell} = electron;

let win;

app.on('ready', function () {
  win = new BrowserWindow({width: 800, height: 600});
  win.loadURL(`file://${__dirname}/index.html`);

var app_menu=[
  {
    label:'پرونده',
    submenu:[
      {
        label:'باز کردن',
        accelerator:'CmdOrCtrl+O',
        click:()=>{
        }
      },
      {
        label:'ذخیره',
        accelerator:'CmdOrCtrl+S',
        click:()=>{
        }
      }
    ]
  },
  {
    label:'سیستم',
    submenu:[
        {
        label:'درباره ما',
        click:()=>
        {
                   shell.openExternal('https://www.dntips.ir');
        }
      },
      {
        label:'خروج',
        accelerator:'CmdOrCtrl+X',
        click:()=>
        {
          win=null;
          app.quit();
        }
      }
    ]
  }
];
تا به اینجای کار، بیشتر کدها برای شما آشناست و فقط تغییرات اندکی در آن‌ها ایجاد شده‌است. مثلا شیء app و سایر اشیاء به طور خلاصه‌تری نوشته شده‌اند. در اینجا دو شیء menu و dialogو shell برای شما جدید هستند. بعد از آن ما یک آرایه را برای منو تدارک دیده‌ایم که نحوه ساخت آن و تعاریفی مثل عنوان، کلید میانبر یا ترکیبی و نحوه انتساب رویدادها را می‌بینید.
 
در خطوط بعدی، یک کار اضافه‌تر را جهت آشنایی بیشتر انجام می‌دهیم. قصد داریم اگر سیستم عامل مکینتاش بود، نام برنامه هم در ابتدای نوار منو نمایش داده شود. به همین جهت در ادامه خطوط زیر را اضافه می‌کنیم:
  if(process.platform=="darwin")
  {
    const app_name=app.getName();
    app_menu.unshift({
      label:app_name
    })
  }
با استفاده از process.platform در node.js می‌توانیم نوع پلتفرم جاری را دریافت کنیم. مقادیر زیر، مقادیری هستند که بازگردانده می‌شوند:

ویندوز
win32 حتی اگر 64 بیتی باشد.
 لینوکس  linux
 مک  darwin
 فری بی اس دی
 freebsd
سولاریس
 sunos
سپس نام برنامه را از شیء app دریافت می‌کنیم و با استفاده از متد unshift، مقادیر داده شده را به ابتدای آرایه اضافه می‌کنیم.

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

دستور app.quit همانطور که از نامش پیداست، باعث خاتمه برنامه می‌شود. ولی یک نکته در اینجا وجود دارد که الزامی به نوشتن کدی برای اینکار نیست. می‌توانید زیرمنوی بالا را به شکل زیر هم بنویسید:
{
        label:'خروج',
        accelerator:'CmdOrCtrl+X',
        role:'close'
 }
خصوصیت role شامل چندین نوع اکشن مانند minimize,close,undo,redo و... می‌باشد که لیست کاملتر آن در اینجا قرار دارد. اگر خصوصیت کلیک و role را همزمان استفاده کنید، خصوصیت role نادیده گرفته خواهد شد.

در انتها با اجرای دو دستور زیر، منو ساخته می‌شود:
  var menu=Menu.buildFromTemplate(app_menu);
  Menu.setApplicationMenu(menu);
در خط اول، منو توسط قالبی که با آرایه‌ها ایجاد کردیم ساخته می‌شود و در خط دوم، منو به برنامه ست می‌شود.
حال قصد داریم برای زیرمنوی «باز کردن فایل» یک دیالوگ open درخواست کنیم. برای این کار از شیء dialog استفاده می‌کنیم. پس خطوط زیر را به رویداد کلیک این زیرمنو اضافه می‌کنیم:
 dialog.showOpenDialog({
             title:'باز کردن فایل متنی',
              properties: [ 'openFile']//[ 'openFile', 'openDirectory', 'multiSelections' ]
             ,filters:[
             {name:'فایل‌های نوشتاری' , extensions:['txt','text']},
             {name:'جهت تست' , extensions:['doc','docx']}
              ]
           },
             (filename)=>{
               if(filename===undefined)
                  return;
               dialog.showMessageBox({title:'پیام اطلاعاتی',type:"info",buttons:['تایید'],message:`the name of file is [${filename}]`});
            });
این متد سه پارامتر دارد که اولین و آخرین پارامتر آن اختیاری می‌باشد. اولین پارامتر آن شیء پنجره است. دومین پارامتر آن، تنظیم یک سری خصوصیات که شامل (پسوند‌های قابل قبول، عنوان، مسیر پیش فرض، قابلیت انتخاب چندگانه، قابلیت باز کردن دایرکتوری و...) می‌شود که لیست کامل آن را می‌توانید در این صفحه ببینید. سومین پارامتر هم که در کد بالا ذکر شده است، callback می‌باشد که خروجی آن، مسیر فایل مورد نظر است و اگر انتخاب چندگانه باشد، آرایه‌ای با نام فایل‌هاست، که همگی آن‌ها به همراه مسیرشان می‌باشند. در صورتیکه کاربر از دیالوگ انصراف بدهد، پارامتر دریافتی با خروجی undefined همراه است.  آخرین دیالوگ هم نمایش یک پیام ساده است که نام فایل جاری را بر میگرداند. اگر خصوصیت buttons را با آرایه خالی مقداردهی کنید، دکمه Ok نمایش داده می‌شود و اگر هم مقداردهی نکنید با خطا روبرو خواهید شد.
برای قسمت ذخیره هم کد زیر را می‌نویسیم:
    dialog.showSaveDialog({
            title:'باز کردن فایل متنی',
             properties: [ 'openFile']//[ 'openFile', 'openDirectory', 'multiSelections' ]
            ,filters:[
            {name:'فایل‌های نوشتاری' , extensions:['txt','text']}
             ]
          },
            (filename)=>{
              if(filename===undefined)
                 return;

           });

حال بهتر است این دیالوگ‌های جاری را هدفمند کنیم و بتوانیم فایل‌های متنی را به کاربر نمایش دهیم، یا آن‌ها را ذخیره کنیم. به همین علت فایل html زیر را نوشته و طبق دستوری که در مقاله «آشنایی با الکترون» فرا گرفتیم، آن را نمایش می‌دهیم:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    Fie Content:<br/>
    <textarea id="TextFile" cols="100" rows="50"></textarea>
 
  </body>
</html>
برای تشکیل ساختار HTML می‌توانید عبارت HTML را تایپ نمایید تا بعد از زدن Enter، ساختار آن به طور خودکار تشکیل شود. سپس محتوا را مثل بالا به شکل دلخواه تغییر می‌دهیم.

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

در نتیجه محتوای callback کدهای دیالوگ open و save را به شکل زیر تغییر می‌دهیم:
Open
 dialog.showOpenDialog({
                 title:'باز کردن فایل متنی',
                  properties: [ 'openFile']//[ 'openFile', 'openDirectory', 'multiSelections' ]
                 ,filters:[
                 {name:'فایل‌های نوشتاری' , extensions:['txt','text']},
                 {name:'جهت تست' , extensions:['doc','docx']}
                  ]
               },
                 (filename)=>{
                   if(filename===undefined)
                      return;

                      win.webContents.send('openFile',filename);
                  // dialog.showMessageBox({title:'پیام اطلاعاتی',type:"info",buttons:['تایید'],message:`the name of file is [${filename}]`});
                });
Save
  dialog.showSaveDialog({
                title:'باز کردن فایل متنی',
                 properties: [ 'openFile']//[ 'openFile', 'openDirectory', 'multiSelections' ]
                ,filters:[
                {name:'فایل‌های نوشتاری' , extensions:['txt','text']}
                 ]
              },
                (filename)=>{
                  if(filename===undefined)
                     return;
                       win.webContents.send('saveFile',filename);
               });
دستور win.webContents.send یک پیام را به صورت Async به سمت RenderProcess مربوطه ارسال میکند. پارامتر اول، عنوان IPC است و پارامتر دوم، پیام IPC است.
برای ایجاد شنونده هم کد زیر را به فایل index.html اضافه می‌کنیم:
  <script>
    const {ipcRenderer} = require('electron');
    var fs=require('fs');

    ipcRenderer.on('openFile', (event, arg) => {
      var content=  fs.readFileSync(String(arg),'utf8');
      document.getElementById("TextFile").value=content;
    });

    ipcRenderer.on('saveFile', (event, arg) =>{
      var content=document.getElementById("TextFile").value;
      fs.writeFileSync(String(arg),content,'utf8');
      alert('ذخیره شد');
    });
    </script>

در اینجا شونده‌هایی را از نوع ipcRenderer ایجاد می‌کنیم و با استفاده از متد on، به پیام‌هایی تحت عنوان‌های مشخص شده گوش فرا می‌دهیم. پیام‌های ارسالی را که حاوی آدرس فایل می‌باشند، به شیءای که از نوع fs می‌باشد، می‌دهند و آن‌ها را می‌خوانند یا می‌نویسند. خواندن و نوشتن فایل، به صورت همزمان صورت میگیرد. ولی اگر دوست دارید که به صورت غیر همزمان پیامی را بخوانید یا بنویسید، باید عبارت Sync را از نام متدها حذف کنید و یک callback را به عنوان پارامتر دوم قرار دهید و محتوای آن را از طریق نوشتن یک پارامتر در سازنده دریافت کنید.

فایل‌های پروژه