نظرات مطالب
بررسی تفصیلی رابطه Many-to-Many در EF Code first
سلام. من ساختاری شبیه به این دارم:
public class Person
{
        //...
        public virtual IList<Center> PreferedCenters { get; set; }
        public virtual IList<Center> ActiveCenters { get; set; }

        public Person()
        {
            PreferedCenters = new List<Center>();
            ActiveCenters = new List<Center>();
        }
}
و کلا Center هم به شکل زیره:
public class Center
{
    //...
    public virtual IList<Person> Persons { get; set; }

    public Center()
    {
        Persons = new List<Person>();
    }
}
مشکلی که دارم اینه که منطقا باید دوتا رابطه‌ی Many-to-many تشکیل بشه: ActiveCenters و PreferedCenters. ولی توی جدول خروجی EF، فقط ستونی به اسم Center_ID ساخته می‌شه و وقتی هم که می‌خوام به سیستم چیزی اضافه کنم اروری شبیه به این می‌گیرم: 
An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll

Additional information: Multiplicity constraint violated. The role 'Center_Persons_Source' of the relationship 'Yarigaran.DataLayer.Center_Persons' has multiplicity 1 or 0..1.
نظرات مطالب
EF Code First #7
- در قسمت HasRequired که Username نباید تعریف شود. در اینجا یک سر دیگر رابطه باید معرفی گردد. همان روابط و کلاس‌هایی که به صورت virtual در کدها آمده.
- در متن ذکر کردم «همین میزان تنظیم کفایت می‌کند و نیازی به استفاده از Fluent API برای معرفی روابط نیست.»
برای بسیاری از تنظیمات EF Code first، اگر پیش فرض‌های آن‌را رعایت کنید، نیازی به هیچگونه تنظیم اضافه‌تری ندارید. مثلا برای رابطه one-to-many فقط کافی است در دو سر رابطه (نه فقط یک سر آن)، تنظیمات زیر را داشته باشید:
// یک سایت که چندین بلاگ دارد
public class Site
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Blog> Blogs { set; get; }
}

public class Blog
{
    public int Id { get; set; }
    public string Name { set; get; }
 
    [ForeignKey("SiteId")]
    public virtual Site Site { get; set; }
    public int SiteId { set; get; }
}
همین مقدار کافی است و پیش فرض‌ها را پوشش می‌دهد. تنظیمات Fluent برای زمانی است که می‌خواهید پیش‌فرض‌ها را بازنویسی کنید. مثلا نام جدول خودکار تشکیل شده توسط آن مدنظر شما نیست. یا حالت بسیار خاصی از روابط مانند مدل‌های خودارجاع دهنده باید تشکیل شود و در این حالت فقط حالت Fluent است که پاسخگوی یک چنین سناریوهایی است.
نظرات مطالب
پیاده سازی پروژه نقاشی (Paint) به صورت شی گرا 2#
با سلام

از مطلب مفیدی که تهیه کردید ممنون.
می‌شود از طریق خاصیت Brush که فعلا فقط خواندنی هست، طرح‌های مختلفی برای پس زمینه اشیاع ایجاد کرد. مانند Paint.net و یا MS Paint.

اگر به صورت زیر تعریف کنیم فکر می‌کنم کمی کامل‌تر باشه!

        private Brush _backgroundBrush;

        /// <summary>
        /// Gets or sets the brush.
        /// </summary>
        /// <value>
        /// The brush.
        /// </value>
        public Brush BackgroundBrush
        {
            get
            {
                return _backgroundBrush;
            }
            private set
            {
                _backgroundBrush = (value != null) ? value : new SolidBrush(BackgroundColor);
            }
        }
        //-------------------------------------[Methode for set brush]--------------------------------------
        public virtual void SetBackgroundBrushAsHatch(HatchStyle hatchStyle)
        {
            HatchBrush brush = new HatchBrush(hatchStyle, BackgroundColor);
            BackgroundBrush = brush;
        }

        public virtual void SetBackgroundBrushAsSolid()
        {
            SolidBrush brush = new SolidBrush(BackgroundColor);
            BackgroundBrush = brush;
        }

        public virtual void SetBackgroundBrushAsLinearGradient()
        {
            LinearGradientBrush brush = new LinearGradientBrush(StartPoint, EndPoint, ForeColor, BackgroundColor);
            BackgroundBrush = brush;
        }

که اگر بخواهیم میتونیم باز بیشتر Customize بکنیمشون.
مطالب
نگاشت IDictionary در Fluent NHibernate

نگاشت خودکار مجموعه‌ها در Fluent NHibernate ساده است و نیاز به تنظیم خاصی ندارد. برای مثال IList به صورت خودکار به Bag ترجمه می‌شود و الی آخر.
البته شاید سؤال بپرسید که این Bag از کجا آمده؟ کلا 6 نوع مجموعه در NHibernate پشتیبانی می‌شوند که شامل Array، Primitive-Array ، Bag ، Set ، List و Map هستند؛ این‌ اسامی هم جهت حفظ سازگاری با جاوا تغییر نکرده‌اند و گرنه معادل‌های آن‌ها در دات نت به این شرح هستند:
Bag=IList
Set=Iesi.Collections.ISet
List=IList
Map=IDictionary

البته در دات نت 4 ، ISet هم به صورت توکار اضافه شده، اما NHibernate از مدت‌ها قبل آن‌را از کتابخانه‌ی Iesi.Collections به عاریت گرفته است. مهم‌ترین تفاوت‌های این مجموعه‌ها هم در پذیرفتن یا عدم پذیرش اعضای تکراری است. Set و Map اعضای تکراری نمی‌پذیرند.
در ادامه می‌خواهیم طرز کار با Map یا همان IDictionary دات نت را بررسی کنیم:

الف) حالتی که نوع کلید و مقدار (در یک عضو Dictionary تعریف شده)، Entity نیستند
using System.Collections.Generic;

namespace Test1.Model12
{
public class User
{
public virtual int Id { set; get; }
public virtual string Name { get; set; }
public virtual IDictionary<string, string> Preferences { get; set; }
}
}

نحوه تعریف نگاشت که مبتنی است بر مشخص سازی تعاریف کلید و مقدار آن جهت تشکیل یک Map یا همان Dictionary :
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;

namespace Test1.Model12
{
public class UserMapping : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
mapping.Id(x => x.Id);
mapping.HasMany(x => x.Preferences)
.AsMap<string>("FieldKey")
.Element("FieldValue", x => x.Type<string>().Length(500));
}
}
}

خروجی SQL متناظر:
create table "User" (
Id INT IDENTITY NOT NULL,
Name NVARCHAR(255) null,
primary key (Id)
)

create table Preferences (
User_id INT not null,
FieldValue NVARCHAR(500) null,
FieldKey NVARCHAR(255) not null,
primary key (User_id, FieldKey)
)

alter table Preferences
add constraint FKD6CB18523B1FD789
foreign key (User_id)
references "User"

ب) حالتی که مقدار، Entity است
using System.Collections.Generic;

namespace Test1.Model13
{
public class User
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IDictionary<string, Property> Properties { get; set; }
}

public class Property
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Value { get; set; }
public virtual User User { get; set; }
}
}

نحوه تعریف نگاشت:
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;

namespace Test1.Model13
{
public class UserMapping : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
mapping.Id(x => x.Id);
mapping.HasMany<Property>(x => x.Properties)
.AsMap<string>("FieldKey")
.Component(x => x.Map(c => c.Id));
}
}
}
خروجی SQL متناظر:
create table "Property" (
Id INT IDENTITY NOT NULL,
Name NVARCHAR(255) null,
Value NVARCHAR(255) null,
User_id INT null,
primary key (Id)
)

create table "User" (
Id INT IDENTITY NOT NULL,
Name NVARCHAR(255) null,
primary key (Id)
)

create table Properties (
User_id INT not null,
Id INT null,
FieldKey NVARCHAR(255) not null,
primary key (User_id, FieldKey)
)

alter table "Property"
add constraint FKF9F4D85A3B1FD7A2
foreign key (User_id)
references "User"

alter table Properties
add constraint FK63646D853B1FD7A2
foreign key (User_id)
references "User"

ج) حالتی که کلید، Entity است
using System;
using System.Collections.Generic;

namespace Test1.Model14
{
public class FormData
{
public virtual int Id { get; set; }
public virtual DateTime? DateTime { get; set; }
public virtual IDictionary<FormField, string> FormPropertyValues { get; set; }
}

public class FormField
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
}

نحوه تعریف نگاشت:
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;

namespace Test1.Model14
{
public class FormDataMapping : IAutoMappingOverride<FormData>
{
public void Override(AutoMapping<FormData> mapping)
{
mapping.Id(x => x.Id);
mapping.HasMany<FormField>(x => x.FormPropertyValues)
.AsEntityMap("FieldId")
.Element("FieldValue", x => x.Type<string>().Length(500))
.Cascade.All();
}
}
}
خروجی SQL متناظر:
create table "FormData" (
Id INT IDENTITY NOT NULL,
DateTime DATETIME null,
primary key (Id)
)

create table FormPropertyValues (
FormData_id INT not null,
FieldValue NVARCHAR(500) null,
FieldId INT not null,
primary key (FormData_id, FieldId)
)

create table "FormField" (
Id INT IDENTITY NOT NULL,
Name NVARCHAR(255) null,
primary key (Id)
)

alter table FormPropertyValues
add constraint FKB807B9C090849E
foreign key (FormData_id)
references "FormData"

alter table FormPropertyValues
add constraint FKB807B97165898A
foreign key (FieldId)
references "FormField"

یک مثال عملی:
امکانات فوق جهت طراحی قسمت ثبت اطلاعات یک برنامه «فرم ساز» مبتنی بر Key-Value بسیار مناسب هستند؛ برای مثال:
برنامه‌ای را در نظر بگیرید که می‌تواند تعدادی خدمات داشته باشد که توسط مدیر برنامه قابل اضافه شدن است؛ برای نمونه خدمات درخواست نصب نرم افزار، خدمات درخواست تعویض کارت پرسنلی، خدمات درخواست مساعده، خدمات ... :
public class Service
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<ServiceFormField> Fields { get; set; }
public virtual IList<ServiceFormData> Forms { get; set; }
}

برای هر خدمات باید بتوان یک فرم طراحی کرد. هر فرم هم از یک سری فیلد خاص آن خدمات تشکیل شده است. برای مثال:
public class ServiceFormField
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual bool IsRequired { get; set; }
public virtual Service Service { get; set; }
}

در اینجا نیازی نیست به ازای هر فیلد جدید واقعا یک فیلد متناظر به دیتابیس اضافه شود و ساختار آن تغییر کند (برخلاف حالت dynamic components که پیشتر در مورد آن بحث شد).
اکنون با داشتن یک خدمات و فیلدهای پویای آن که توسط مدیربرنامه تعریف شده‌اند، می‌توان اطلاعات وارد کرد. مهم‌ترین نکته‌ی آن هم IDictionary تعریف شده است که حاوی لیستی از فیلدها به همراه مقادیر وارد شده توسط کاربر خواهد بود:
public class ServiceFormData
{
public virtual int Id { get; set; }
public virtual IDictionary<ServiceFormField, string> FormPropertyValues { get; set; }
public virtual DateTime? DateTime { get; set; }
public virtual Service Service { get; set; }
}

در مورد نحوه نگاشت آن هم در حالت «ج» فوق توضیح داده شد.

مطالب
آموزش TypeScript #5
در ادامه مباحث شی گرایی در TypeScript قصد داریم به مباحث مربوط به interface و طریقه استفاده از آن بپردازیم. همانند زبان‌های دات نتی در TypeScript نیز به راحتی می‌توانید interface تعریف کنید. در یک اینترفیس اجازه پیاده سازی هیچ تابعی را ندارید و فقط باید عنوان و پارامتر‌های ورودی و نوع خروجی آن را تعیین کنید. برای تعریف اینترفیس از کلمه کلیدی interface به صورت زیر استفاده خواهیم کرد.
export interface ILogger {
  log(message: string): void;
}
همان طور در پست‌های قبلی مشاهده شد از کلمه کلیدی export برای عمومی کردن اینترفیس استفاده می‌کنیم. یعنی این اینترفیس از بیرون ماژول خود نیز قابل دسترسی است.
حال نیاز به کلاسی داریم که این اینترفیس را پیاده سازی کند. این پیاده سازی به صورت زیر انجام می‌گیرد:
export class Logger implements ILogger
{
}
یا:
export class AnnoyingLogger implements ILogger {
   log(message: string): void{
         alert(message);
     } 
}
همانند دات نت یک کلاس می‌تواند چندین اینترفیس را پیاده سازی کند.(اصطلاحا به این روش explicit implementation یا پیاده سازی صریح می‌گویند)
export class MyClass implements IFirstInterface, ISecondInterface
{

}
*یکی از قابلیت جالب و کارآمد زبان TypeScript این است که در هنگام کار با اینترفیس‌ها حتما نیازی به پیاده سازی صریح نیست. اگر یک object تمام متغیر‌ها و توابع مورد نیاز یک اینترفیس را پیاده سازی کند به راحتی همانند روش explicit emplementation می‌توان از آن object استفاده کرد.  به این قابلیت Duck Typing  می‌گویند. مثال:
IPerson {
   firstName: string;
   lastName: string;
} 
class Person implements IPerson {
  constructor(public firstName: string, public lastName: string) {
  }
}

varpersonA: IPerson = newPerson('Masoud', 'Pakdel'); //expilict
varpersonB: IPerson = { firstName: 'Ashkan', lastName: 'Shahram'}; // duck typing
همان طور که می‌بینید object  دوم به نام personB تمام متغیر‌ها ی مورد نیاز اینترفیس IPerson را پیاده سازی کرده است در نتییجه کامپایلر همان رفتاری را که با object اول به نام personA دارد را با آن نیز خواهد داشت.

پیاده سازی چند اینترفیس به صورت همزمان
همانند دات نت که یک کلاس فقط می‌تواند از یک کلاس ارث ببرد ولی می‌تواند n  تا اینترفیس را پیاده سازی کند در TypeScript نیز چنین قوانینی وجود دارد. یعنی یک اینترفیس می‌تواند چندین اینترفیس دیگر را توسعه دهد(extend) و کلاسی که این اینترفیس را پیاده سازی می‌کند باید تمام توابع اینترفیس‌ها را پیاده سازی کند. مثال:
interface IMover {
 move() : void;
}

interface IShaker {
 shake() : void;
} 

interface IMoverShaker extends IMover, IShaker {
}
class MoverShaker implements IMoverShaker {
 move() {
 }
 shake() {
 }
}
*به کلمات کلیدی extends و implements و طریقه به کار گیری آن‌ها دقت کنید.

 instanceof

از instanceof زمانی استفاده می‌کنیم که قصد داشته باشیم که یک instance را با یک نوع مشخص مقایسه کنیم. اگر instance مربوطه از نوع مشخص باشد یا از این نوع ارث برده باشد مقدار true برگشت داده می‌شود در غیر این صورت مقدار false خواهد بود.
یک مثال:
var isLogger = logger instanceof Utilities.Logger; 
var isLogger = logger instanceof Utilities.AnnoyingLogger; 
var isLogger = logger instanceof Utilities.Formatter;
Method overriding
در TypeScript می‌توان مانند زبان‌های شی گرای دیگر Method overriding را پیاده سازی کرد. یعنی می‌توان متد‌های کلاس پایه را در کلاس مشتق شده تحریف کرد. با یک مثال به شرح این مورد خواهم پرداخت.
فرض کنید یک کلاس پایه به صورت زیر داریم:
class BaseEmployee
{   
    constructor (public fname: string,public lname: string) 
    {  
    }  
    sayInfo() 
    {  
       alert('this is base class method');
    }  
}
کلاس دیگری به نام Employee می‌سازیم که کلاس بالا را توسعه می‌دهد(یا به اصطلاح از کلاس بالا ارث می‌برد).
class Employee extends BaseEmployee
{  
   sayInfo() 
     {  
        alert('this is derived class method');
     }  
}  

window.onload = () =>  
{   
    var first: BaseEmployee= new Employee();     
    first.sayInfo();  
    var second: BaseEmployee = new BaseEmployee(); 
    second.sayInfo(); 
}
نکته مهم این است که دیگر خبری از کلمه کلیدی virtual برای مشخص کردن توابعی که قصد overriding آن‌ها را داریم نیست. تمام توابع که عمومی هستند را می‌توان override کرد.
*اگر در کلاس مشتق شده قصد داشته باشیم که به توابع و فیلد‌های کلاس پایه اشاره کنیم باید از کلمه کلیدی super استفاده کنیم.(معادل base در #C).
مثال:
class Animal {
    constructor (public name: string) {
    }
}

class Dog extends Animal {    
      constructor (public name: string, public age:number)
      {
        super(name);
      }

    sayHello() {
alert(super.name);
 } }
اگر به سازنده کلاس مشتق شده دقت کنید خواهید دید که پارامتر name را به سازنده کلاس پایه پاس دادیم: کد معادل در #C به صورت زیر است:
public class Dog : Animal 
{    
      public Dog (string name, int age):base(name)
      {
      }
}
در تابع sayHello نیز با استفاده از کلمه کلیدی super به فیلد name در کلاس پایه دسترسی خواهیم داشت.

*دقت کنید که مباحث مربوط به interface و private modifier و Type safety که پیش‌تر در مورد آن‌ها بحث شد، فقط در فایل‌های TypeScript و در هنگام کد نویسی و طراحی معنی دار هستند، زیرا بعد از کامپایل فایل‌های ts این مفاهیم در Javascript پشتیبانی نمی‌شوند در نتیجه هیچ مورد استفاده هم نخواهد داشت.

ادامه دارد...