অবজেক্টের জন্য লিনকিউ সহ পেজিং


94

আপনি কীভাবে একটি লিনকিউ কোয়েরিতে পেজিং বাস্তবায়ন করবেন? আসলে আপাতত, স্কেল টপ ফাংশনটি অনুকরণ করতে পারলে আমি সন্তুষ্ট হব। যাইহোক, আমি নিশ্চিত যে পূর্ণ পেজিং সমর্থনটির প্রয়োজন যেভাবেই পরে যাই হোক না কেন।

var queryResult = from o in objects
                  where ...
                  select new
                      {
                         A = o.a,
                         B = o.b
                      }
                   ????????? TOP 10????????

উত্তর:


234

আপনি Skipএবং Takeএক্সটেনশন পদ্ধতিগুলি সন্ধান করছেন। Skipফলাফলটি প্রথম এন উপাদানগুলির পরে চলে যায়, বাকীটি ফিরিয়ে দেয়; Takeফলাফলগুলিতে প্রথম এন উপাদানগুলি প্রদান করে, বাকি কোনও উপাদান ফেলে দেয়।

এই পদ্ধতিগুলি কীভাবে ব্যবহার করতে হয় সে সম্পর্কে আরও তথ্যের জন্য এমএসডিএন দেখুন: http://msdn.microsoft.com/en-us/library/bb386988.aspx

ধরে নিই যে আপনি ইতিমধ্যে অ্যাকাউন্টটি নিচ্ছেন যে পৃষ্ঠা নম্বরটি 0 থেকে শুরু হওয়া উচিত (মন্তব্যগুলিতে প্রস্তাবিত প্রতি 1 টি হ্রাস) আপনি এটি এটি করতে পারেন:

int numberOfObjectsPerPage = 10;
var queryResultPage = queryResult
  .Skip(numberOfObjectsPerPage * pageNumber)
  .Take(numberOfObjectsPerPage);

অন্যথায় @ অ্যালভিনের পরামর্শ অনুসারে

int numberOfObjectsPerPage = 10;
var queryResultPage = queryResult
  .Skip(numberOfObjectsPerPage * (pageNumber - 1))
  .Take(numberOfObjectsPerPage);

7
আমি কি এসকিউএল-তে একটি বিশাল ডাটাবেস সহ একই কৌশলটি ব্যবহার করব, এটি কি পুরো টেবিলটিকে প্রথমে মেমরির মধ্যে নেবে এবং তারপরে অযাচিতগুলিকে ফেলে দেবে?
ব্যবহারকারী 256890

4
আপনি যদি হুডের নীচে কী চলছে সে বিষয়ে আগ্রহী হন, তবে বেশিরভাগ লিনকিউ ডেটাবেস ড্রাইভাররা প্রকৃত এসকিউএল যেটি কার্যকর করা হচ্ছে তার জন্য ডিবাগ আউটপুট তথ্য পাওয়ার একটি উপায় সরবরাহ করে।
ডেভিড ফেফার

পেজলিস্ট <টি> ক্লাস সম্পর্কে রব কনারি ব্লগ করেছে যা আপনাকে শুরু করতে সহায়তা করতে পারে। blog.wekeroad.com/blog/aspnet-mvc-pagedlistt
jrotello

49
এর ফলে প্রথম পৃষ্ঠাটি এড়িয়ে যেতে পারে যদি পৃষ্ঠা সংখ্যাটি শূন্য (0) ভিত্তিক না হয়। যদি পৃষ্ঠা সংখ্যাটি 1 দিয়ে শুরু হয়, তাই এটি ব্যবহার করুন ".স্কিপ (সংখ্যাঅফজেক্টস পেপার পেজ * (পৃষ্ঠা সংখ্যা - 1))"
অ্যালভিন

ফলে প্রাপ্ত এসকিউএল কেমন হবে, ডাটাবেসটি হিট করার মতো?
ফয়েজ

54

ব্যবহার করা Skipএবং Takeঅবশ্যই যাওয়ার উপায়। যদি আমি এটি বাস্তবায়ন করতাম, তবে সম্ভবত প্যাগিং হ্যান্ডেল করার জন্য আমি কোডটি নিজের সম্প্রসারণ পদ্ধতিটি লিখতাম (কোডটি আরও পাঠযোগ্য। বাস্তবায়ন অবশ্যই ব্যবহার করতে পারে Skipএবং Take:

static class PagingUtils {
  public static IEnumerable<T> Page<T>(this IEnumerable<T> en, int pageSize, int page) {
    return en.Skip(page * pageSize).Take(pageSize);
  }
  public static IQueryable<T> Page<T>(this IQueryable<T> en, int pageSize, int page) {
    return en.Skip(page * pageSize).Take(pageSize);
  }
}

ক্লাসটি দুটি এক্সটেনশন পদ্ধতি সংজ্ঞায়িত করে - একটির জন্য IEnumerableএবং একটি এর জন্য IQueryable, যার অর্থ আপনি এটি ব্যবহার করতে পারেন LINQ থেকে অবজেক্ট এবং লিনকিউ থেকে এসকিউএল উভয় (ডাটাবেস ক্যোয়ারী লেখার সময়, সংকলকটি IQueryableসংস্করণটি বেছে নেবে )।

আপনার পেজিং প্রয়োজনীয়তার উপর নির্ভর করে আপনি কিছু অতিরিক্ত আচরণও যুক্ত করতে পারেন (উদাহরণস্বরূপ নেতিবাচক pageSizeবা pageমান হ্যান্ডেল করার জন্য )। আপনার ক্যোয়ারিতে আপনি কীভাবে এই এক্সটেনশন পদ্ধতিটি ব্যবহার করবেন তা এখানে একটি উদাহরণ রয়েছে:

var q = (from p in products
         where p.Show == true
         select new { p.Name }).Page(10, pageIndex);

4
আমি বিশ্বাস করি এটি পুরো ফলাফল সেটটি ফিরিয়ে দেবে এবং তারপরে সার্ভারের পরিবর্তে মেমরি ফিল্টার করবে। এটি যদি এসকিউএল হয় তবে একটি ডাটাবেসের বিরুদ্ধে বিশাল পারফরম্যান্স হিট।
jvenema

4
@ জাভেনিমা আপনি ঠিক বলেছেন যেহেতু এটি এর IEnumerableপরিবর্তে ইন্টারফেসটি ব্যবহার করছে IQueryableপুরো ডেটাবেস টেবিলটি টানবে যা একটি বড় পারফরম্যান্স হিট হবে।
ডেভিড ফেফার

4
এটি অবশ্যই IQueryableডেটাবেসের প্রশ্নের সাথেও কাজ করার জন্য আপনি খুব সহজেই একটি ওভারলোড যুক্ত করতে পারেন (আমি উত্তরটি সম্পাদনা করে এটি যুক্ত করেছি)। এটি কিছুটা দুর্ভাগ্যজনক যে আপনি কোডটি সম্পূর্ণ জেনেরিক উপায়ে লিখতে পারবেন না (হাস্কেলের ক্ষেত্রে এটি টাইপ শ্রেণীর মাধ্যমে সম্ভব হবে)। মূল প্রশ্নটি অবজেক্টগুলিতে লিনকিউ উল্লেখ করেছে, তাই আমি কেবল একটি ওভারলোড লিখেছি।
টমাস পেট্রিসেক

আমি নিজেই এটিকে বাস্তবায়নের বিষয়ে ভাবছিলাম। আমি কিছুটা অবাক হয়েছি যে এটি স্ট্যান্ডার্ড বাস্তবায়নের অংশ নয়। নমুনা কোডের জন্য ধন্যবাদ!
মাইকেল রিচার্ডসন

4
আমি মনে করি উদাহরণটি হওয়া উচিত: পাবলিক স্ট্যাটিক আইকোয়্যারেবল <T> পৃষ্ঠা <T> (... ইত্যাদি)
ডেভিড টালবট

37

অবজেক্টগুলিতে লিনকিউ ব্যবহার করার সময় আমার পেজিংয়ের পারফরম্যান্ট অ্যাপ্রোচটি এখানে রয়েছে:

public static IEnumerable<IEnumerable<T>> Page<T>(this IEnumerable<T> source, int pageSize)
{
    Contract.Requires(source != null);
    Contract.Requires(pageSize > 0);
    Contract.Ensures(Contract.Result<IEnumerable<IEnumerable<T>>>() != null);

    using (var enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            var currentPage = new List<T>(pageSize)
            {
                enumerator.Current
            };

            while (currentPage.Count < pageSize && enumerator.MoveNext())
            {
                currentPage.Add(enumerator.Current);
            }
            yield return new ReadOnlyCollection<T>(currentPage);
        }
    }
}

এটি তখন এর মতো ব্যবহার করা যেতে পারে:

var items = Enumerable.Range(0, 12);

foreach(var page in items.Page(3))
{
    // Do something with each page
    foreach(var item in page)
    {
        // Do something with the item in the current page       
    }
}

এই আবর্জনার কোনওটিই নয় Skipএবং Takeযদি আপনি একাধিক পৃষ্ঠায় আগ্রহী হন তবে এটি অত্যন্ত অদক্ষ।


4
এটি অ্যাজুর এসকিউএল ডেটা ওয়্যারহাউসের সাথে সত্তা ফ্রেমওয়ার্কে কাজ করে, যা
স্কিপ

4
এটি কেবল চুরি করে আমার সাধারণ লিবিতে ফেলে দিতে হয়েছিল, ধন্যবাদ! বনাম অস্পষ্টতা Paginateঅপসারণ করার জন্য আমি কেবল পদ্ধতির নামকরণ করেছি । nounverb
গ্যাব্রিয়েলিয়াস


6

এটি কারও সাহায্য করবে কিনা জানি না, তবে আমি এটি আমার উদ্দেশ্যে দরকারী বলে মনে করেছি:

private static IEnumerable<T> PagedIterator<T>(IEnumerable<T> objectList, int PageSize)
{
    var page = 0;
    var recordCount = objectList.Count();
    var pageCount = (int)((recordCount + PageSize)/PageSize);

    if (recordCount < 1)
    {
        yield break;
    }

    while (page < pageCount)
    {
        var pageData = objectList.Skip(PageSize*page).Take(PageSize).ToList();

        foreach (var rd in pageData)
        {
            yield return rd;
        }
        page++;
    }
}

এটি ব্যবহার করতে আপনার কিছু লিনক ক্যোয়ারী থাকবে এবং পৃষ্ঠার আকারের সাথে ফলকটি একটি ফোরচ লুপে পাস করুন:

var results = from a in dbContext.Authors
              where a.PublishDate > someDate
              orderby a.Publisher
              select a;

foreach(var author in PagedIterator(results, 100))
{
    // Do Stuff
}

সুতরাং এটি প্রতিটি লেখককে একবারে 100 জন লেখক আনতে পুনরাবৃত্তি করবে।


গণনাটি (যেমন) সংগ্রহটি অঙ্কিত করে, আপনি এটিকে পাশাপাশি তালিকাতে রূপান্তর করতে পারেন এবং সূচীগুলি দিয়ে পুনরাবৃত্তি করতে পারেন।
কেরবার

5

সম্পাদনা - অপরিহার্য স্কিপ (0) অপরিহার্য হিসাবে এটি প্রয়োজনীয় নয়

var queryResult = (from o in objects where ...
                      select new
                      {
                          A = o.a,
                          B = o.b
                      }
                  ).Take(10);

4
আপনার নেওয়া / ছেড়ে যাওয়া পদ্ধতির ক্রমটি পরিবর্তন করা উচিত নয়? নেওয়ার পরে (0) এড়িয়ে যান কোনও অর্থ হয় না। আপনার উদাহরণটি ক্যোয়ারী স্টাইলে দেওয়ার জন্য ধন্যবাদ।
ব্যবহারকারী 256890

4
না, তিনি ঠিক বলেছেন। Take10, Skip0 প্রথম 10 উপাদান নেয়। Skip0 অর্থহীন এবং কখনও করা উচিত নয়। এবং ক্রম Takeএবং Skipবিষয়গুলির ক্রম - Skip10, Take10 এ উপাদানগুলিকে 10-20 লাগে; Take10, Skip10 কোনও উপাদান ফেরত দেয় না।
ডেভিড ফেফার

টেক কল করার আগে আপনার ক্যোয়ারির চারপাশে বন্ধনীগুলিরও প্রয়োজন হতে পারে। (থেকে ... নির্বাচন করুন ...) নিন (10)। আমি স্ট্রিং নির্বাচন করে কনস্ট্রাক্টকে ফোন করেছি। বন্ধনী ব্যতীত টেক অনুসন্ধানের ফলাফল সীমাবদ্ধ না করে স্ট্রিংয়ের প্রথম 10 টি অক্ষর
ফেরৎ পাঠিয়েছে

3
var pages = items.Select((item, index) => new { item, Page = index / batchSize }).GroupBy(g => g.Page);

ব্যাচসাইজ স্পষ্টতই একটি পূর্ণসংখ্যা হবে। এটি পূর্ণসংখ্যার সাথে দশমিক স্থানগুলি সহজেই ফেলে দেয় এই সুবিধাটি গ্রহণ করে।

আমি এই প্রতিক্রিয়াটির সাথে অর্ধেক রসিকতা করছি, তবে এটি আপনি যা করতে চান তা করবে এবং এটি পিছিয়ে গেছে, আপনি যদি এটি করেন তবে আপনাকে একটি বড় পারফরম্যান্স জরিমানা দিতে হবে না

pages.First(p => p.Key == thePage)

এই সমাধানটি লিনকটোএন্টিটিগুলির জন্য নয়, এমনকি এটিকে একটি ভাল ক্যোয়ারিতে রূপান্তর করতে পারে কিনা তা আমি জানি না।


3

লুকাজয়েডের উত্তরের অনুরূপ আমি আইকিউয়েরেবলের জন্য একটি এক্সটেনশন তৈরি করেছি।

   public static IEnumerable<IEnumerable<T>> PageIterator<T>(this IQueryable<T> source, int pageSize)
            {
                Contract.Requires(source != null);
                Contract.Requires(pageSize > 0);
                Contract.Ensures(Contract.Result<IEnumerable<IQueryable<T>>>() != null);

                using (var enumerator = source.GetEnumerator())
                {
                    while (enumerator.MoveNext())
                    {
                        var currentPage = new List<T>(pageSize)
                        {
                            enumerator.Current
                        };

                        while (currentPage.Count < pageSize && enumerator.MoveNext())
                        {
                            currentPage.Add(enumerator.Current);
                        }
                        yield return new ReadOnlyCollection<T>(currentPage);
                    }
                }
            }

স্কিপ বা টেক সমর্থিত না হলে এটি কার্যকর।


1

আমি এই এক্সটেনশন পদ্ধতিটি ব্যবহার করি:

public static IQueryable<T> Page<T, TResult>(this IQueryable<T> obj, int page, int pageSize, System.Linq.Expressions.Expression<Func<T, TResult>> keySelector, bool asc, out int rowsCount)
{
    rowsCount = obj.Count();
    int innerRows = rowsCount - (page * pageSize);
    if (innerRows < 0)
    {
        innerRows = 0;
    }
    if (asc)
        return obj.OrderByDescending(keySelector).Take(innerRows).OrderBy(keySelector).Take(pageSize).AsQueryable();
    else
        return obj.OrderBy(keySelector).Take(innerRows).OrderByDescending(keySelector).Take(pageSize).AsQueryable();
}

public IEnumerable<Data> GetAll(int RowIndex, int PageSize, string SortExpression)
{
    int totalRows;
    int pageIndex = RowIndex / PageSize;

    List<Data> data= new List<Data>();
    IEnumerable<Data> dataPage;

    bool asc = !SortExpression.Contains("DESC");
    switch (SortExpression.Split(' ')[0])
    {
        case "ColumnName":
            dataPage = DataContext.Data.Page(pageIndex, PageSize, p => p.ColumnName, asc, out totalRows);
            break;
        default:
            dataPage = DataContext.vwClientDetails1s.Page(pageIndex, PageSize, p => p.IdColumn, asc, out totalRows);
            break;
    }

    foreach (var d in dataPage)
    {
        clients.Add(d);
    }

    return data;
}
public int CountAll()
{
    return DataContext.Data.Count();
}

1
    public LightDataTable PagerSelection(int pageNumber, int setsPerPage, Func<LightDataRow, bool> prection = null)
    {
        this.setsPerPage = setsPerPage;
        this.pageNumber = pageNumber > 0 ? pageNumber - 1 : pageNumber;
        if (!ValidatePagerByPageNumber(pageNumber))
            return this;

        var rowList = rows.Cast<LightDataRow>();
        if (prection != null)
            rowList = rows.Where(prection).ToList();

        if (!rowList.Any())
            return new LightDataTable() { TablePrimaryKey = this.tablePrimaryKey };
        //if (rowList.Count() < (pageNumber * setsPerPage))
        //    return new LightDataTable(new LightDataRowCollection(rowList)) { TablePrimaryKey = this.tablePrimaryKey };

        return new LightDataTable(new LightDataRowCollection(rowList.Skip(this.pageNumber * setsPerPage).Take(setsPerPage).ToList())) { TablePrimaryKey = this.tablePrimaryKey };
  }

এই আমি কি করেছি। সাধারণত আপনি 1 এ শুরু করেন তবে IList এ আপনি 0 দিয়ে শুরু করেন so সুতরাং আপনার যদি 152 টি সারি থাকে তার মানে আপনার 8 টি পেজিং রয়েছে তবে IList এ আপনার কেবল 7. আছে hop আশা করি এটি আপনার পক্ষে বিষয়টিকে পরিষ্কার করে তুলতে পারে



1

দুটি প্রধান বিকল্প রয়েছে:

.NET> = 4.0 গতিশীল লিংক :

  1. System.Linq.Dynamic ব্যবহার করে যুক্ত করুন; উপরে.
  2. ব্যবহার: var people = people.AsQueryable().OrderBy("Make ASC, Year DESC").ToList();

আপনি এটি নুগেট দ্বারাও পেতে পারেন ।

.NET <4.0 সম্প্রসারণ পদ্ধতি :

private static readonly Hashtable accessors = new Hashtable();

private static readonly Hashtable callSites = new Hashtable();

private static CallSite<Func<CallSite, object, object>> GetCallSiteLocked(string name) {
    var callSite = (CallSite<Func<CallSite, object, object>>)callSites[name];
    if(callSite == null)
    {
        callSites[name] = callSite = CallSite<Func<CallSite, object, object>>.Create(
                    Binder.GetMember(CSharpBinderFlags.None, name, typeof(AccessorCache),
                new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
    }
    return callSite;
}

internal static Func<dynamic,object> GetAccessor(string name)
{
    Func<dynamic, object> accessor = (Func<dynamic, object>)accessors[name];
    if (accessor == null)
    {
        lock (accessors )
        {
            accessor = (Func<dynamic, object>)accessors[name];
            if (accessor == null)
            {
                if(name.IndexOf('.') >= 0) {
                    string[] props = name.Split('.');
                    CallSite<Func<CallSite, object, object>>[] arr = Array.ConvertAll(props, GetCallSiteLocked);
                    accessor = target =>
                    {
                        object val = (object)target;
                        for (int i = 0; i < arr.Length; i++)
                        {
                            var cs = arr[i];
                            val = cs.Target(cs, val);
                        }
                        return val;
                    };
                } else {
                    var callSite = GetCallSiteLocked(name);
                    accessor = target =>
                    {
                        return callSite.Target(callSite, (object)target);
                    };
                }
                accessors[name] = accessor;
            }
        }
    }
    return accessor;
}
public static IOrderedEnumerable<dynamic> OrderBy(this IEnumerable<dynamic> source, string property)
{
    return Enumerable.OrderBy<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> OrderByDescending(this IEnumerable<dynamic> source, string property)
{
    return Enumerable.OrderByDescending<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> ThenBy(this IOrderedEnumerable<dynamic> source, string property)
{
    return Enumerable.ThenBy<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
}
public static IOrderedEnumerable<dynamic> ThenByDescending(this IOrderedEnumerable<dynamic> source, string property)
{
    return Enumerable.ThenByDescending<dynamic, object>(source, AccessorCache.GetAccessor(property), Comparer<object>.Default);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.