نظرات مطالب
روش‌هایی برای بهبود سرعت برنامه‌های مبتنی بر Entity framework
- در کنفرانس techEd 2014 در جلسه «Entity Framework: Building Applications with Entity Framework 6» کار با Full text search در EF 6، جزو مثال‌های مطرح شده‌است.
- روش دوم هم در اینجا «Full text search in Microsoft's Entity Framework».
- روش سوم با استفاده از IDbCommandInterceptor در اینجا «Microsoft's Full Text Search in Entity Framework 6»
مطالب
شروع به کار با EF Core 1.0 - قسمت 8 - بررسی رابطه‌ی Many-to-Many
در مطلب «بررسی تفصیلی رابطه Many-to-Many در EF Code first» نحوه‌ی مدلسازی رابطه‌ی چند به چند را در EF 6.x بررسی کردیم. یک چنین رابطه‌ای که به همراه مدیریت خودکار join table آن است (جدول BlogPostsJoinTags در شکل زیر)، در EF Core 1.0 RTM پشتیبانی نمی‌شود.


البته همیشه درخواست کنترل این جدول واسط که کاملا از دیدگاه ORMها (تمام آن‌ها) مخفی است، وجود داشته‌است و قرار است این پشتیبانی توسط مفهوم ویژه‌ای به نام shadow properties به نگارش‌های بعدی EF Core اضافه شود.
اما فعلا در نگارش اول آن، توصیه شده‌است که رابطه‌ی many-to-many را به صورت دو رابطه‌ی one-to-many مدلسازی کنید که در ادامه آن‌را بررسی خواهیم کرد. بنابراین پیشنیاز آن مطالعه‌ی مطلب «شروع به کار با EF Core 1.0 - قسمت 7 - بررسی رابطه‌ی One-to-Many» می‌باشد.


مدلسازی موجودیت‌های یک رابطه‌ی چند به چند در EF Core 1.0 RTM توسط Fluent API

در اینجا نحوه‌ی مدلسازی یک رابطه‌ی چند به چند را توسط دو رابطه‌ی one-to-many مشاهده می‌کنید. تنها تفاوت آن با EF 6.x، قید صریح جدول واسط BlogPostsJoinTags است که یک چنین جدولی در EF 6.x به صورت خودکار تشکیل شده و مدیریت می‌شود و کاملا از دید برنامه مخفی است. اما در اینجا (در نگارش اول EF Core) نیاز است این جدول واسط را از حالت مخفی خارج کرد و سپس دو رابطه‌ی یک به چند را به جداول مطالب و تگ‌های آن‌ها تشکیل داد.
مزیت این حالت، دسترسی کامل به طراحی جدول واسط، توسط برنامه است. بنابراین اگر به هر دلیلی نیاز به افزودن خواص بیشتری به این جدول ویژه دارید، اکنون امکان آن میسر است.
    public class Tags
    {
        public Tags()
        {
            BlogPostsJoinTags = new HashSet<BlogPostsJoinTags>();
        }

        public int Id { get; set; }
        public string Name { get; set; }

        public virtual ICollection<BlogPostsJoinTags> BlogPostsJoinTags { get; set; }
    }

    public class BlogPostsJoinTags
    {
        public virtual BlogPosts BlogPost { get; set; }
        public int BlogPostId { get; set; }

        public virtual Tags Tag { get; set; }
        public int TagId { get; set; }
    }

    public class BlogPosts
    {
        public BlogPosts()
        {
            BlogPostsJoinTags = new HashSet<BlogPostsJoinTags>();
        }

        public int Id { get; set; }
        public string Title { get; set; }
        public string Body { get; set; }

        public virtual ICollection<BlogPostsJoinTags> BlogPostsJoinTags { get; set; }
    }
پس از آن باید Context برنامه را نیز جهت ذکر صریح رابطه‌ی یک به چند، ویرایش کرد. با متدهای HasOne و WithMany در مطلب قبل «شروع به کار با EF Core 1.0 - قسمت 7 - بررسی رابطه‌ی One-to-Many» آشنا شدیم و علت نیاز به ذکر صریح آن‌ها، وجود بیش از یک سر رابطه در جدول واسط BlogPostsJoinTags است. در این حالت یافتن InversePropertyها توسط EF Core میسر نیست و حتما باید از یک طرف شروع و سمت دیگر را مشخص کرد.
به علاوه در اینجا تعریف یک composite key را هم بر روی خواص کلید خارجی جدول واسط مشاهده می‌کنید. وجود این کلید ترکیبی سبب خواهد شد که ملزم به ثبت هر دو Id (کلیدهای جداول مطلب و تگ) در حین ثبت در این جدول شویم (یا قید اجباری هر دو طرف رابطه).
    public class MyDBDataContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Data Source=(local);Initial Catalog=testdb2;Integrated Security = true");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<BlogPosts>(entity =>
            {
                entity.Property(e => e.Title)
                    .IsRequired()
                    .HasMaxLength(450);
            });

            modelBuilder.Entity<Tags>(entity =>
            {
                entity.Property(e => e.Name)
                    .IsRequired()
                    .HasMaxLength(450);
            });

            modelBuilder.Entity<BlogPostsJoinTags>(entity =>
            {
                entity.HasKey(e => new { e.TagId, e.BlogPostId })
                    .HasName("PK_dbo.BlogPostsJoinTags");

                entity.HasIndex(e => e.BlogPostId)
                    .HasName("IX_BlogPostId");

                entity.HasIndex(e => e.TagId)
                    .HasName("IX_TagId");

                entity.HasOne(d => d.BlogPost)
                    .WithMany(p => p.BlogPostsJoinTags)
                    .HasForeignKey(d => d.BlogPostId)
                    .HasConstraintName("FK_dbo.BlogPostsJoinTags_dbo.BlogPosts_BlogPostId");

                entity.HasOne(d => d.Tag)
                    .WithMany(p => p.BlogPostsJoinTags)
                    .HasForeignKey(d => d.TagId)
                    .HasConstraintName("FK_dbo.BlogPostsJoinTags_dbo.Tags_TagId");
            });
        }

        public virtual DbSet<BlogPosts> BlogPosts { get; set; }
        public virtual DbSet<BlogPostsJoinTags> BlogPostsJoinTags { get; set; }
        public virtual DbSet<Tags> Tags { get; set; }
    }


مدلسازی موجودیت‌های یک رابطه‌ی چند به چند در EF Core 1.0 RTM توسط Data Annotations

در حالت مدلسازی توسط ویژگی‌ها، ذکر InversePropertyها و همچنین ForeignKeyها مقداری واضح‌تر به نظر می‌رسند. به علاوه، یک سری از تنظیمات هم معادل data annotations ایی ندارند؛ مانند composite key تعریف شده‌ی بر روی خواص جدول واسط و همچنین ایندکس‌های تعریف شده، که حتما باید توسط Fluent API تنظیم شوند.
    public class Tags
    {
        public Tags()
        {
            BlogPostsJoinTags = new HashSet<BlogPostsJoinTags>();
        }

        public int Id { get; set; }

        [Required]
        [MaxLength(450)]
        public string Name { get; set; }

        [InverseProperty("Tag")]
        public virtual ICollection<BlogPostsJoinTags> BlogPostsJoinTags { get; set; }
    }

    public class BlogPostsJoinTags
    {
        [ForeignKey("BlogPostId")]
        [InverseProperty("BlogPostsJoinTags")]
        public virtual BlogPosts BlogPost { get; set; }
        public int BlogPostId { get; set; }

        [ForeignKey("TagId")]
        [InverseProperty("BlogPostsJoinTags")]
        public virtual Tags Tag { get; set; }
        public int TagId { get; set; }
    }

    public class BlogPosts
    {
        public BlogPosts()
        {
            BlogPostsJoinTags = new HashSet<BlogPostsJoinTags>();
        }

        public int Id { get; set; }

        [Required]
        [MaxLength(450)]
        public string Title { get; set; }

        public string Body { get; set; }

        [InverseProperty("BlogPost")]
        public virtual ICollection<BlogPostsJoinTags> BlogPostsJoinTags { get; set; }
    }

    public class MyDBDataContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Data Source=(local);Initial Catalog=testdb2;Integrated Security = true");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<BlogPostsJoinTags>(entity =>
            {
                entity.HasKey(e => new { e.TagId, e.BlogPostId })
                    .HasName("PK_dbo.BlogPostsJoinTags");

                entity.HasIndex(e => e.BlogPostId)
                    .HasName("IX_BlogPostId");

                entity.HasIndex(e => e.TagId)
                    .HasName("IX_TagId");
            });
        }

        public virtual DbSet<BlogPosts> BlogPosts { get; set; }
        public virtual DbSet<BlogPostsJoinTags> BlogPostsJoinTags { get; set; }
        public virtual DbSet<Tags> Tags { get; set; }
    }
همانطور که در مطلب «شروع به کار با EF Core 1.0 - قسمت 6 - تعیین نوع‌های داده و ویژگی‌های آن‌ها» نیز عنوان شد، علت تنظیم MaxLength به عدد 450 این است که بتوان بر روی این ستون ایندکس ایجاد کرد.


نحوه‌ی ثبت اطلاعات در دو رابطه‌ی یک به چند به همراه جدول واسط

در EF 6.x، کار مقدار دهی Idهای جدول واسط به صورت خودکار انجام می‌شود. در اینجا این مقدار دهی را باید به صورت صریح انجام داد:
 var post = new BlogPosts { ... };
context.BlogPosts.Add(post);

var tag = new Tags { ... };
context.Tags.Add(tag);

var postTag = new BlogPostsJoinTags { Tag = tag, BlogPost = post };
context.PostsTags.Add(postTag);

context.SaveChanges();


نحوه‌ی واکشی اطلاعات به هم مرتبط در دو رابطه‌ی یک به چند به همراه جدول واسط

در مورد متدهای Include و ThenInclude در مطلب «شروع به کار با EF Core 1.0 - قسمت 7 - بررسی رابطه‌ی One-to-Many» پیشتر بحث شد.
            BlogPosts post1 = this.BlogPosts
                  .Include(blogPosts => blogPosts.BlogPostsJoinTags)
                    .ThenInclude(joinTags => joinTags.Tag)
                  .First(blogPosts => blogPosts.Id == 1);
            IEnumerable<Tags> post1Tags = post1.BlogPostsJoinTags.Select(x => x.Tag);
در اینجا اگر می‌خواهیم به لیست تمام برچسب‌های اولین مطلب دسترسی پیدا کنیم، ابتدا باید رابطه‌ی جدول واسط را Include کنیم. سپس چون در همین سطح می‌خواهیم به سطح بعدی تگ‌های مرتبط برسیم، باید از متد الحاقی جدید ThenInclude استفاده کرد. در غیراینصورت در سطر بعدی، post1.BlogPostsJoinTags نال خواهد بود و همچنین حاوی لیست تگ‌ها نیز نخواهد بود.


یک نکته‌ی تکمیلی
وضعیت پشتیبانی از رابطه‌ی many-to-many را همانند EF 6.x در EF Core، در اینجا می‌توانید پیگیری کنید.
اشتراک‌ها
پیاده سازی یک پروژه با ASP.NET Core Web API

Ticketier project | ASP.NET Core Web API CRUD and Search | .NET 7 API | Full Course

Full Course Ticketier project with ASP.NET Core Web API (.NET 7 API ) and  Entity Framework Core covering CRUD and Search step by step
In this video, we will create an ASP.NET Core Web API (.NET 7) project called Ticketier and implement full CRUD and Search functionality into it.
The focus of this project is to show you how you can build new ASP.NET Core Web API (.NET 7) project from 0 to 100 and implement CRUD and Search in it.

we will learn these topics together:
Entities
Dtos
Context
ORM
Http Methods
Swagger
AutoMapper
IQueryable
Where clause 

پیاده سازی یک پروژه با ASP.NET Core Web API
اشتراک‌ها
بررسی تغییرات انجام شده در Entity Framework 7

With the new Version 7, Entity Framework is moving away from legacy systems and duplications which have accumulated in recent years. As a slim-line new development it will be available for .NET Core, and therefore also WinRT, whilst in addition allowing access to NoSQL databases.This session will show exactly what has changed and how you can benefit from the new possibilities. 

بررسی تغییرات انجام شده در Entity Framework 7
اشتراک‌ها
بررسی بهبودهای کارآیی در NET 7.

TL;DR: .NET 7 is fast. Really fast. A thousand performance-impacting PRs went into runtime and core libraries this release, never mind all the improvements in ASP.NET Core and Windows Forms and Entity Framework and beyond. It’s the fastest .NET ever. If your manager asks you why your project should upgrade to .NET 7, you can say “in addition to all the new functionality in the release, .NET 7 is super fast.” 

بررسی بهبودهای کارآیی در NET 7.