فرشید عزیزی
فرشید عزیزی
خواندن ۶ دقیقه·۲ سال پیش

دوره آموزشی Entity FrameWork Core - قسمت يازدهم

انواع رابطه :

  • رابطه يک به چند(one-to-many) :
    در قسمت قبل/دهم از اين دوره آموزشي بصورت کامل به آن پرداخته شد و مثال هايي از آن را با هم ديديده ايم. بنابراين از تکرار آن در اينجا خودداري مي کنم.
  • رابطه يک به يک(One-to-one) : روابط یک به یک دارای ویژگی ناوبری مرجع(reference navigation property) در هر دو طرف هستند. آنها از همان قراردادهای روابط یک به چند پیروی می کنند، اما یک شاخص منحصر به فرد به عنوان پراپرتي کلید خارجی معرفی می شود تا اطمینان حاصل شود که فقط یک نمونه موجوديت وابسته به هر نمونه موجوديت اصلی مرتبط است.
public class Blog { public int BlogId { get; set; } public string Url { get; set; } public BlogImage BlogImage { get; set; } } public class BlogImage { public int BlogImageId { get; set; } public byte[] Image { get; set; } public string Caption { get; set; } public int BlogId { get; set; } public Blog Blog { get; set; } }

خوب EF بر اساس توانایی خود در تشخیص ویژگی کلید خارجی، یکی از موجوديت ها را به عنوان وابسته(dependent) انتخاب می کند. اگر موجودیت اشتباهی به عنوان وابسته انتخاب شود، می‌توانید از Fluent API برای اصلاح آن استفاده کنید.

هنگام پیکربندی رابطه با Fluent API، از متدهای HasOne و WithOne استفاده می‌کنیم.

هنگام پیکربندی کلید خارجی، باید نوع موجودیت وابسته را مشخص کنید - به پارامتر generic ارائه شده به HasForeignKey در قطعه کد زیر توجه کنید. در یک رابطه یک به چند، واضح است که موجودیت دارای ناوبری مرجع، وابسته و موجودیتي که مجموعه دارد، اصلی است. اما در رابطه یک به یک اینطور نیست - از این رو نیاز به تعریف صریح آن است.

internal class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<BlogImage> BlogImages { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasOne(b => b.BlogImage) .WithOne(i => i.Blog) .HasForeignKey<BlogImage>(b => b.BlogForeignKey); } } public class Blog { public int BlogId { get; set; } public string Url { get; set; } public BlogImage BlogImage { get; set; } } public class BlogImage { public int BlogImageId { get; set; } public byte[] Image { get; set; } public string Caption { get; set; }= public int BlogForeignKey { get; set; } public Blog Blog { get; set; } }

سمت وابسته(dependent) به طور پیش فرض اختیاری(optional) در نظر گرفته می شود، اما می تواند در بصورت الزامي(required) پیکربندی شود. یک سناریوی رایج برای این،reference owned typeها هستند که به طور پیش فرض از table splitting استفاده می کنند.

modelBuilder.Entity<Order>( ob => { ob.OwnsOne( o => o.ShippingAddress, sa => { sa.Property(p => p.Street).IsRequired(); sa.Property(p => p.City).IsRequired(); }); ob.Navigation(o => o.ShippingAddress) .IsRequired(); });

با این پیکربندی، ستون های مربوط به ShippingAddress به عنوان غیر قابل تهی شدن(non-nullable) در پایگاه داده علامت گذاری می شوند.

اگر از non-nullable reference types استفاده می کنید، فراخوانی IsRequired ضروری نیست.

  • رابطه چند به چند(Many-to-many) :
    روابط چند به چند به یک ویژگی ناوبری مجموعه در هر دو طرف نیاز دارند. آنها بر اساس قرارداد مانند انواع دیگر روابط کشف خواهند شد.
public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public ICollection<Tag> Tags { get; set; } } public class Tag { public string TagId { get; set; } public ICollection<Post> Posts { get; set; } }

روشی که این رابطه در پایگاه داده پیاده سازی می شود توسط یک جدول join است که حاوی کلیدهای خارجی برای هر دو Post و Tag است.

به عنوان مثال این چیزی است که EF در یک پایگاه داده رابطه ای برای مدل فوق ایجاد می کند.

CREATE TABLE [Posts] ( [PostId] int NOT NULL IDENTITY, [Title] nvarchar(max) NULL, [Content] nvarchar(max) NULL, CONSTRAINT [PK_Posts] PRIMARY KEY ([PostId]) ); CREATE TABLE [Tags] ( [TagId] nvarchar(450) NOT NULL, CONSTRAINT [PK_Tags] PRIMARY KEY ([TagId]) ); CREATE TABLE [PostTag] ( [PostsId] int NOT NULL, [TagsId] nvarchar(450) NOT NULL, CONSTRAINT [PK_PostTag] PRIMARY KEY ([PostsId], [TagsId]), CONSTRAINT [FK_PostTag_Posts_PostsId] FOREIGN KEY ([PostsId]) REFERENCES [Posts] ([PostId]) ON DELETE CASCADE, CONSTRAINT [FK_PostTag_Tags_TagsId] FOREIGN KEY ([TagsId]) REFERENCES [Tags] ([TagId]) ON DELETE CASCADE );

در اینجا، EF یک نوع موجودیت را برای نشان دادن join table ایجاد می کند که به عنوان join entity type نامیده می شود.

یش از یک رابطه چند به چند می‌تواند در مدل وجود داشته باشد، بنابراین به join entity type باید یک نام منحصر به فرد داده شود، در این مورد PostTag.


پیکر بندی Join entity type :

این عمل را می توان از طریق UsingEntity انجام داد :

modelBuilder .Entity<Post>() .HasMany(p => p.Tags) .WithMany(p => p.Posts) .UsingEntity(j => j.ToTable(&quotPostTags&quot));


داده های آزمایشی (Model seed data) برای join entity type:

modelBuilder .Entity<Post>() .HasData(new Post { PostId = 1, Title = &quotFirst&quot }); modelBuilder .Entity<Tag>() .HasData(new Tag { TagId = &quotef&quot }); modelBuilder .Entity<Post>() .HasMany(p => p.Tags) .WithMany(p => p.Posts) .UsingEntity(j => j.HasData(new { PostsPostId = 1, TagsTagId = &quotef&quot }));

داده های اضافی(پراپرتی ها/ویژگی ها) را می توان در join entity type ذخیره کرد، اما برای این کار بهتر است یک نوع CLR سفارشی ایجاد کنید. هنگام پیکربندی رابطه با یک join entity type سفارشی، هر دو کلید خارجی باید به صراحت مشخص شوند :

internal class MyContext : DbContext { public MyContext(DbContextOptions<MyContext> options) : base(options) { } public DbSet<Post> Posts { get; set; } public DbSet<Tag> Tags { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Post>() .HasMany(p => p.Tags) .WithMany(p => p.Posts) .UsingEntity<PostTag>( j => j .HasOne(pt => pt.Tag) .WithMany(t => t.PostTags) .HasForeignKey(pt => pt.TagId), j => j .HasOne(pt => pt.Post) .WithMany(p => p.PostTags) .HasForeignKey(pt => pt.PostId), j => { j.Property(pt => pt.PublicationDate).HasDefaultValueSql(&quotCURRENT_TIMESTAMP&quot); j.HasKey(t => new { t.PostId, t.TagId }); }); } } public class Post { public int PostId { get; set; } public string Title { get; set; } public string Content { get; set; } public ICollection<Tag> Tags { get; set; } public List<PostTag> PostTags { get; set; } } public class Tag { public string TagId { get; set; } public ICollection<Post> Posts { get; set; } public List<PostTag> PostTags { get; set; } } public class PostTag { public DateTime PublicationDate { get; set; } public int PostId { get; set; } public Post Post { get; set; } public string TagId { get; set; } public Tag Tag { get; set; } }


پیکربندی Joining relationships :

توجه داشته باشید EF از دو رابطه یک به چند در join entity type برای نشان دادن رابطه چند به چند استفاده می کند. می توانید این روابط را در آرگومان های UsingEntity پیکربندی کنید:

modelBuilder.Entity<Post>() .HasMany(p => p.Tags) .WithMany(p => p.Posts) .UsingEntity<Dictionary<string, object>>( &quotPostTag&quot, j => j .HasOne<Tag>() .WithMany() .HasForeignKey(&quotTagId&quot) .HasConstraintName(&quotFK_PostTag_Tags_TagId&quot) .OnDelete(DeleteBehavior.Cascade), j => j .HasOne<Post>() .WithMany() .HasForeignKey(&quotPostId&quot) .HasConstraintName(&quotFK_PostTag_Posts_PostId&quot) .OnDelete(DeleteBehavior.ClientCascade));


بیشتر بخوانید : دوره آموزشی Entity FrameWork Core - قسمت دوازدهم

بیشتر بخوانید : دوره آموزشی Entity FrameWork Core

بیشتر بخوانید : نقشه راه توسعه دهندگان Asp.NET Core

https://zarinp.al/farshidazizi

دوره آموزشیentity framework coreef coreASP.NET COREget set
Software Engineer
شاید از این پست‌ها خوشتان بیاید