رابطه یک به یک در روش Code First

چهارشنبه 7 بهمن 1394

در این مقاله قصد داریم نحوه ایجاد رابطه یک به یک بین کلاس ها در روش Code First را آموزش دهیم .از آنجاییکه در روش Code First کلاس های ما به جداول نگاشت می شوند لازم است که رابطه بین آنها به صورت درست پیاده سازی شود .

رابطه یک به یک در روش Code First

همان طور که میدانید Entity Framework یک ORM است که کار ارتباط با منبع داده را برای ما ساده کرده است .برای استفاده از EF روش های مختلفی وجود دارد که یکی از این روش ها Code First است .دراین روش کلاس هایی که نوشته ایم به جداول تبدیل می شوند .از انجایی که بین جداول ارتباطات مختلفی وجود دارد بنابراین باید بین کلاس هایی که در روش code first ایجاد می کنیم هم رابطه برقرار کنیم تا به صورت مناسب به جداول ما نگاشت شوند .

هر گاه یک موجودیت ما با یک موجودیت دیگر در رابطه باشد بین آنها یک Relation برقرار است .برای این رابطه انواع مختلفی وجود دارد .از انجایی که Entity Framework یک ORM است و قرار است کار نگاشت جداول به کلاس های برنامه و یا بر عکس تبدیل   کلاس ها به جداول (در روش code First) بر عهده دارد قصد داریم در این مقاله نحوه پیاده سازی انواع ارتباطات بین موجودیت ها را بررسی کنیم .

رابطه یک به چند

در این نوع رابطه یک نمونه از موجودیت می تواند با یک یا چند نمونه از موجودیت دیگر در ارتباط باشد .

رابطه  چند به چند

هر نمونه از موجودیت اول می تواند با یک یا چند نمونه از موجودیت دیگر ارتباط داشته باشد و برعکس.

کرد، زیرا Entity Framework به صورت خودکار با پردازش کلاس ها رابطه ها را شناسایی خواهد کرد.
ارتباطی که بین جداول وجود دارد در دیتابیس به نام foreign keys شناخته میشود . foreign keys در واقع ستونی و یا چند ستون است که ارتباط بین دیتاهای دو جدول را برقرار می کند .همان طور که گفته شد به صورت کلی سه نوع ارتباط بین جداول وجود دارد

1 – ارتباط یک به یک

2- ارتباط یک به چند

3- ارتباط چند به چند

هر سه نوع ارتباط توسط Entity Framework پشتیبانی میشود .در این مقاله راجع به ارتباط یک به یک صحبت می کنیم .این نوع ارتباط  زمانی اتفاق می افتد که کلید اصلی یک جدول به عنوان کلید خارجی جدول دیگر باشد . Entity Framework(به اختصار EF) به صورت پیش فرض کلید اصلی در جدول اول را به عنوان کلید خارجی در جدول دوم در نظر می گیرد.در این نوع ارتباط یک رکورد و با صفر رکورد از جدول اول با یک رکورد از جدول دوم ارتباط دارند.

برای درک بهتر این موضوع  دو موجودیت زیر را در نظر بگیرید.این دو موجودیت به نام های EmployeeDetails و Employee هستند.هر یک رکورد از جدول Employee تنها یک رکورد متناظر در جدول EmployeeDetails دارد.کلید اصلی در جدول Employee به عنوان هم کلید اصلی و هم کلید خارجی در جدول EmployeeDetails در نظر گرفته می شود .

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

استفاده از Data Annotation

فرم ورک EF دسته های مختلفی از Data Annotation ها را برای استفاده برنامه نویسان فراهم کرده است .در داخل کلاس وابسته که یک موجودیت از کلاس اصلی تعریف کرده ایم از Data Annotation ایی به نام ForeignKey استفاده می کنیم .همان طور که میدانید هر ارتباطی در EF دو سر دارد .برای سر دیگر رابطه EF از کلید اصلی استفاده خواهد کرد .اگر چندین ارتباط بین کلاس ها وجود داشته باشد دیگر EF قادر به مدیریت کردن این ارتباطات نیست .این عدم توانایی به دلیل Map  نبودن navigation property در یک سمت و   پراپرتی متناظر در سمت دیگر است .در این حالت استفاده از صفت های می تواند برای شما راه گشا باشد .یکی از این صفت ها InverseProperty است .

کلاس Employee به صورت زیر است

    [Table("Employee")]  
    public partial class Employee  
    {  
        [DatabaseGenerated(DatabaseGeneratedOption.None)]  
        public int EmployeeId  
        {  
            get;  
            set;  
        }  
        [Required]  
        [StringLength(50)]  
        public string FirstName  
        {  
            get;  
            set;  
        }  
        [Required]  
        [StringLength(50)]  
        public string LastName  
        {  
            get;  
            set;  
        }  
        [StringLength(50)]  
        public string MiddleName  
        {  
            get;  
            set;  
        }  
        public virtual EmployeeDetail 
        {  
            get;  
            set;  
        }  
    }  

کلاس EmployeeDetail به صورت زیر است

    [Table("EmployeeDetail")]  
    public partial class EmployeeDetail  
    {  
        [Key, ForeignKey("Employee")]  
        [DatabaseGenerated(DatabaseGeneratedOption.None)]  
        public int EmployeeId  
        {  
            get;  
            set;  
        }  
        [StringLength(10)]  
        public string Gender  
        {  
            get;  
            set;  
        }  
        [StringLength(255)]  
        public string EmailAddress  
        {  
            get;  
            set;  
        }  
        [StringLength(50)]  
        public string PhoneNumber  
        {  
            get;  
            set;  
        }  
        public virtual EmployeeEmployee  
        {  
            get;  
            set;  
        }  
    }  

کلاس context که در واقع مانند دیتابیس در برنامه ما می باشد به صورت زیر است

    public partial class EFTestModel: DbContext  
    {  
        public EFTestModel(): base("name=entities")  
        {}  
        public virtualDbSet < Employee > Employees  
        {  
            get;  
            set;  
        }  
        public virtual DbSet < EmployeeDetail > EmployeeDetails  
        {  
            get;  
            set;  
        }  
        protected override void OnModelCreating(DbModelBuildermodelBuilder)  
        {}  
    }  

همان طور که دیدید بین دوجدول EmployeeDetail و Employee یک ارتباط یک به یک برقرار شد .برای تست رابطه بالا یک برنامه کنسول نوشته ایم و جزییات مربوط به یک کارمند را چاپ کرده ایم .

    static void Main(string[] args)  
    {  
        //Configure One to One Relationship in Entity Framework Using Code First Approach  
        Employee employee;  
        using(var context = newEntityModel.EFTestModel())  
        {  
            employee = context.Employees.FirstOrDefault();  
            Console.WriteLine("Employee Details");  
            Console.WriteLine("Employee Name:" + string.Join(" ", newobject[]  
            {  
                employee.FirstName, employee.LastName  
            }));  
            Console.WriteLine("Employee Email Address:" + employee.EmployeeDetail.EmailAddress);  
        }  
        Console.ReadLine();  
    }  

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

استفاده از Fluent API

اگر علاقه مند به استفاده از Attribute ها برای توصیف پراپرتی ها نیستید می توانید از روش Fluent API استفاده کنید .همان ویژگی ها در اینجا هم وجود دارند منتها به سبک برنامه نویسی و نه به صورت دادن صفت به پراپرتی ها.در کجا باید قید های Fluent ApI را تعریف کنیم ؟ در پاسخ باید گفت در داخل کلاسی که از DBContext مشتق شده است ، و در داخل متد OnModelCreationg که به صورت Override است
محل تعریف این قیود، کلاس Context که از کلاس DbContext مشتق شده است، می‌باشد و در اینجا، کار با تحریف متد OnModelCreating شروع می‌شود:

برای ایجاد ارتباط یک به یک بین موجودیت ها می توان از Fluent API هم استفاده کرد .با استفاده از hasKey می توان به تعریف Primary Key   پرداخت .به کد زیر توجه کنید

protected override void OnModelCreating(DbModelBuildermodelBuilder)  
{  
    modelBuilder.Entity < Customer > ().HasKey(p => p.CustomerId);  
    modelBuilder.Entity < Customer > ().HasOptional(e => e.CustomerDetail).WithRequired(e => e.Customer);  
} 

در خط اول برای جدول Employee یک کلید اصلی از فیلدهای کلاس به نام CustomerId در نظر گرفته ایم .در خط دوم هم تعیین کرده ایم که کدام جدول جدول اصلی و کدام جدول وابسته است .

ساختار جداول Customer   و CustomerDetail   به صورت زیر است

    [Table("Customer")]  
    public partial class Customer  
    {  
        [DatabaseGenerated(DatabaseGeneratedOption.None)]  
        public int CustomerId  
        {  
            get;  
            set;  
        }  
        [Required]  
        [StringLength(50)]  
        public string FirstName  
        {  
            get;  
            set;  
        }  
        [Required]  
        [StringLength(50)]  
        public string LastName  
        {  
            get;  
            set;  
        }  
        [StringLength(50)]  
        public string MiddleName  
        {  
            get;  
            set;  
        }  
        public virtual CustomerDetailCustomerDetail  
        {  
            get;  
            set;  
        }  
    }  
    [Table("CustomerDetail")]  
    public partial class CustomerDetail  
    {  
        [Key]  
        [DatabaseGenerated(DatabaseGeneratedOption.None)]  
        public int CustomerId  
        {  
            get;  
            set;  
        }  
        [StringLength(255)]  
        public string EmailAddress  
        {  
            get;  
            set;  
        }  
        [StringLength(50)]  
        public string PhoneNumber  
        {  
            get;  
            set;  
        }  
        public virtual CustomerCustomer  
        {  
            get;  
            set;  
        }  
    }  

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

    static void Main(string[] args)  
    {  
        //Configure One to One Relationship in Entity Framework Using Code First Approach  
        Customer c;  
        using(var context = newEntityModel.EFTestModel())  
        {  
            c = context.Customers.FirstOrDefault();  
            Console.WriteLine("Customer Details");  
            Console.WriteLine("Customer Name:" + string.Join(" ", newobject[]  
            {  
                c.FirstName, c.LastName  
            }));  
            Console.WriteLine("Customer Email Address:" + c.CustomerDetail.EmailAddress);  
        }  
        Console.ReadLine();  
    }  

خروجی به صورت زیر است .

 

فایل های ضمیمه

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید