رابطه های فریم ورک Entity با مهاجرت در Code First

فریم ورک entity 6 دارای ویژگی هایی است که کار را برای برنامه نویس راحت می کند. در این مقاله نگاهی می اندازیم به مهاجرت در فریم ورک entity که از code frst استفاده شده باشد.

رابطه های فریم ورک Entity با مهاجرت در Code First

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

یک به یک

یک به چند

چند به چند

اگر شما نمی توانید معنای آن را به طور کامل حس کنید، نترسید. ما هر یک را در این مقاله بررسی خواهیم کرد. برای انجام این کار باید از Entity Framework Code First استفاده کرد.

نصب

ویژوال استادیو را باز کرده و در آن یک console application باز نمایید. کار شما در متد Main static  واقع در Program.cs می باشد. پیشنهاد می کنم برای جلوگیری از ابهام نام Program.cs را با Start.cs عوض کنید.

سپس Package Manager Console  را مانند شکل باز کرده :


و کد زیر را در آن باز کنید :

PM>Install-Package EntityFramework -Version 6.1.3

یک مدل مانند زیر با نام User بسازید :

class User
{
    public long Id { get; set; }
    [Required]
    [StringLength(25)]
    public string Name { get; set; }
    [StringLength(25)]
    public string Company { get; set; }
    public virtual Password Password { get; set; }
    public virtual ICollection<Role> Roles { get; set; }
    public virtual ICollection<Program> Programs { get; set; }
}

این یک مدل است که اکثر روابط (Relation ها) از آن مشتق می شود. گاهی اوقات آن را شیء والد می نامیم. فریم ورک Entity از [Key] برای تبدیل آن پروپرتی به کلید اصلی استفاده می کند. همچنین Data Anotation ها برای اعتبار سنجی استفاده می شوند مانند : [Required] . یهنی این فیلد اجباری است و نباید خالی رد شود.

نکته : اگر از data base first استفاده کرده بودیم [Required] یعنی تیک Allow null برداشته شود.

سپس مدل های زیر را هم می سازیم :

class Password
{
    [Key, ForeignKey("User")]
    public long UserId { get; set; }
    [Required]
    [StringLength(256)]
    public string PasswordHash { get; set; }
    [Required]
    [StringLength(3)]
    public string EncryptionMethod { get; set; }
    public virtual User User { get; set; }
}
class Role
{
    public long Id { get; set; }
    public long UserId { get; set; }
    [Required]
    public string Name { get; set; }
}
class Program
{
    public long Id { get; set; }
    [Required]
    [StringLength(25)]
    public string Name { get; set; }
    public virtual ICollection<User> Users { get; set; }
}

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

class ApplicationDbContext : DbContext
{
    public ApplicationDbContext() : base(@"Data Source=(LocalDb)\v11.0;
        AttachDbFilename=C:\Dev\MyFullPath\EfRelationshipsCodeFirstDb.mdf;
        Integrated Security=True;
        Connect Timeout=30")
    {
    }

    public DbSet<User> Users { get; set; }
    public DbSet<Password> Passwords { get; set; }
    public DbSet<Role> Roles { get; set; }
    public DbSet<Program> Programs { get; set; }
}

حال خط زیر را در Package Manager Console می نویسیم :

PM> Enable-Migrations -EnableAutomaticMigrations

یک به یک

شما باید یک متد برای پر کردن در فایل Configuration.cs که ساختیم داشته باشید. برای پر کردن داده :

context.Users.AddOrUpdate(new User
{
    Id = 1,
    Name = "Joe"
});
context.Passwords.AddOrUpdate(new Password
{
    UserId = 1,
    EncryptionMethod = "MD5",
    PasswordHash = "blue"
});

برای اعمال تغییرات درون بانک اطلاعاتی کافی است در Package Manager Console تایپ نمایید :

PM> Update-Database

در این مثال هر کاربر دارای یک کلمه عبور می باشد. جدول کلمه عبور درون خودش دارای Id نیست بلکه هر کلمه عبور مربوط به یک UserId است که کلید اصلی می باشد. کلید های فرعی در SQL Server ایندکس می شوند بنابراین نیاز به اضافه کردن صفت [Index] به کلید های رابطه نیست. این خبر خوبی برای کارایی است هنگامی که شما برای مجموعه داده های بزرگ کوئری می زنید.

برای بررسی این می توان کدهای زیر را در متد Main static نوشت.

var context = new ApplicationDbContext();
var user = context.Users.Include("Password").First(x => x.Id == 1);
Console.WriteLine("What is your name?");
Console.WriteLine(user.Name);
Console.WriteLine("What is your favorite color?");
Console.WriteLine(user.Password.PasswordHash);

یک به چند

هر User می تواند دارای بیش از یک Role باشد. در Configuration.cs داریم :

context.Roles.AddOrUpdate(
    new Role
    {
        Id = 1,
        UserId = 1,
        Name = "to find the holy grail"
    },
    new Role
    {
        Id = 2,
        UserId = 1,
        Name = "Uh?"
    });

برای بروزرسانی بانک اطلاعاتی :

PM> Update-Database

مثال زیر نشان می دهد که هر User دارای چند Roles است. در Main بنویسید :

user = context.Users.Include("Roles").First(x => x.Id == 1);
Console.WriteLine("What is your quest?");
Console.WriteLine(user.Roles.First(x => x.Id == 1).Name);
Console.WriteLine("What is the capital of Assyria?");
Console.WriteLine(user.Roles.First(x => x.Id == 2).Name);

فیلد UserId در جدول Roles به عنوان کلید خارجی در نظر گرفته می شود. این به موتور بانک اطلاعاتی می فهماند که یک جدول رابطه ای داریم. شما در Server Explorer دارید :

چند به چند

مهمترین رابطه در روابط بانک اطلاعاتی می باشد. در این مثال نشان داده می شود که هر User دارای چند Programs می باشد و هر programs مربوط به چند User می باشد.

در Configuration.cs داریم :

context.Users.AddOrUpdate(new User
{
    Id = 2,
    Name = "Jane"
});
context.Programs.AddOrUpdate(
    new Program
    {
        Id = 1,
        Name = "A"
    },
    new Program
    {
        Id = 2,
        Name = "B"
    });

سپس اضافه کنید :

var user1 = context.Users.Include("Programs").First(x => x.Id == 1);
var user2 = context.Users.Include("Programs").First(x => x.Id == 2);
if (user1.Programs.Count == 0)
{
    foreach (var prog in context.Programs)
    {
        user1.Programs.Add(prog);
    }
    context.SaveChanges();
}
if (user2.Programs.Count == 0)
{
    foreach (var prog in context.Programs)
    {
        user2.Programs.Add(prog);
    }
    context.SaveChanges();
}

سپس در Main داریم :

var users = context.Users.Include("Programs").ToList();
users.ForEach(u =>
{
    var progs = u.Programs.ToList();
    progs.ForEach(p =>
    {
        Console.WriteLine("User " + u.Name + " has program " + p.Name);
    });
});

همچنین برای اینکه ببینیم کدام User ها مربوط به کدام Programs هستند کد زیر را به Main اضافه کنید :

var programs = context.Programs.Include("Users").ToList();
programs.ForEach(p =>
{
    var usrs = p.Users.ToList();
    usrs.ForEach(u =>
    {
        Console.WriteLine("Program " + p.Name + " has user " + u.Name);
    });
});

Server Explorer :

اگر از برنامه اجرا بگیرید:

نتیجه گیری :
فریم ورک Entity به شما قابلیت های زیادی برای کار با داده می دهد. اگر درک خوبی از این مفاهیم داشته باشید می توانید به راحتی روابط بانک اطلاعاتی را پیاده سازی کنید.

آموزش سی شارپ

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