عنوان:

‫مرتب سازی رکوردها به صورت اتفاقی در Entity framework


نویسنده: وحید نصیری
تاریخ: ۱۳۹۱/۰۷/۰۷ ۹:۵۸
آدرس: www.dntips.ir
یکی از انواع روش‌هایی که در SQL Server و مشتقات آن برای نمایش رکوردها به صورت اتفاقی مورد استفاده قرار می‌گیرد، استفاده از کوئری زیر است:
SELECT * FROM table
ORDER BY NEWID()
سؤال: ترجمه و معادل کوئری فوق در Entity framework به چه صورتی است؟
پاسخ:
یک مثال کامل را در این زمینه در ادامه ملاحظه می‌کنید:
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;

namespace Sample
{
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }

    public class MyContext : DbContext
    {
        public DbSet<User> Users { get; set; }
    }

    public class Configuration : DbMigrationsConfiguration<MyContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }

        protected override void Seed(MyContext context)
        {
            context.Users.Add(new User { Name = "User 1", Age = 20 });
            context.Users.Add(new User { Name = "User 2", Age = 25 });
            context.Users.Add(new User { Name = "User 3", Age = 30 });
            context.Users.Add(new User { Name = "User 4", Age = 35 });
            context.Users.Add(new User { Name = "User 5", Age = 40 });
            base.Seed(context);
        }
    }

    public static class Test
    {
        public static void RunTests()
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());

            using (var context = new MyContext())
            {
               var randomListOfUsers =
                        context.Users
                               .Where(person => person.Age >= 25 && person.Age < 40)
                               .OrderBy(person => Guid.NewGuid())
                               .ToList();

               foreach (var person in randomListOfUsers)
                   Console.WriteLine("{0}:{1}", person.Name, person.Age);
            }
        }
    }
}
تنها نکته مهم آن سطر ذیل است که برای مرتب سازی اتفاقی استفاده شده است:
.OrderBy(person => Guid.NewGuid())
که معادل
ORDER BY NEWID()
در SQL Server است.

خروجی SQL تولیدی کوئری LINQ فوق را نیز در ادامه مشاهده می‌کنید:
SELECT 
[Project1].[Id] AS [Id], 
[Project1].[Name] AS [Name], 
[Project1].[Age] AS [Age]
FROM ( SELECT 
NEWID() AS [C1], ------ Guid created here
[Extent1].[Id] AS [Id], 
[Extent1].[Name] AS [Name], 
[Extent1].[Age] AS [Age]
FROM [dbo].[Users] AS [Extent1]
WHERE ([Extent1].[Age] >= 25) AND ([Extent1].[Age] < 40)
)  AS [Project1]
ORDER BY [Project1].[C1] ASC  ------ Used for sorting here

نظرات

  • حسین مرادی نیا در ۱۳۹۱/۰۷/۰۷ ۱۳:۳۰
    مرسی بابت مطلب خوبتون
    اما کاربرد این روش مرتب سازی در کجاست؟
    به شخصه اولین بار است که این روش مرتب سازی را میبینم.
    • وحید نصیری در ۱۳۹۱/۰۷/۰۷ ۱۳:۳۲
      یک نمونه از کاربرد آن
      • حسین مرادی نیا در ۱۳۹۱/۰۷/۰۷ ۱۳:۳۶
        مرسی
        جالب بود
        دقت نکرده بودم
  • سیروان عفیفی در ۱۳۹۱/۰۷/۰۷ ۱۸:۳۸
    مرسی واقعا مفید بود.
  • محمد صاحب در ۱۳۹۱/۰۷/۰۸ ۱۱:۴۳
    این روش رو جداول حجیم سرعت رو میاره پایین تو محیط sql میشه از TABLESAMPLE استفاده کرد که متاسفانه معادلی براش تو linq نیست و...
    آقای نصیری یه روش هم به این صورته
     SELECT * FROM Table1
      WHERE (ABS(CAST(
      (BINARY_CHECKSUM(*) *
      RAND()) as int)) % 100) < 10
    
     میخواستم بدونم این روش رو میشه به linq تبدیل کرد؟
    • وحید نصیری در ۱۳۹۱/۰۷/۰۸ ۱۲:۴۴
      خیر. کوئری‌های EF طوری طراحی شدن که قابل انتقال به بانک‌های اطلاعاتی دیگر هم باشند و بتونید با تغییر کانکشن استرینگ بدون نگرانی آنچنانی، واقعا از یک بانک اطلاعاتی دیگر استفاده کنید.
      در EF می‌شود raw sql هم نوشت: (^). در این حالت برنامه شما صرفا به بانک اطلاعاتی مورد استفاده گره خواهد خورد و اگر مثلا این BINARY_CHECKSUM در SQLite وجود خارجی نداشت، این برنامه و سیستم دیگر قابل انتقال نخواهند بود.
  • سیروان عفیفی در ۱۳۹۱/۰۷/۰۸ ۱۶:۰
    یه سری دستورات هستند که EF معادلی براشون توی SQL نداره به طور مثال EF نمی‌دونه که متد Parse رو در SQL به چی تبدیل کنه،به طور مثال کد زیر :
    var query = (from list in dbContext.Packages
                                 where list.Id == Int32.Parse(Request["Id"].ToString())
                                 select list).FirstOrDefault();
    باید به صورت زیر تغییر بدیم :
    Int32 ID = Int32.Parse(Request["Id"].ToString());
     var query = (from list in dbContext.Packages
                                 where list.Id == ID
                                 select list).FirstOrDefault();
    به نظرتون توی نسخه‌های بعد این مشکلات رو برطرف می‌کنن؟
    • وحید نصیری در ۱۳۹۱/۰۷/۰۸ ۱۶:۳۹
      لطفا از موضوع بحث که مرتب سازی اتفاقی است خارج نشید.
      در مورد پیشنهادها و انتقادهای مرتبط با EF می‌تونید به اینجا مراجعه کنید: (^)
  • احسان آرک در ۱۳۹۲/۱۰/۲۱ ۱۹:۲
    با سلام
    آیا میشود جدولی که هر آیتم آن میتواند لیستی از همین جدول را داشته باشد در entity مرتب کرد؟ مانند یک لیست تو در تو.
    • وحید نصیری در ۱۳۹۲/۱۰/۲۱ ۱۹:۳۰
      در مطلب «مباحث تکمیلی مدل‌های خود ارجاع دهنده در EF Code first» بعد از Where (که نوشته for TreeViewHelper) یک OrderBy قرار بدید. نمونه‌اش همین مرتب سازی کامنت‌های تو در توی سایت جاری است بر اساس Id آن‌ها از بالا به پایین ذیل هر مطلب.