Random row from Linq to Sql

前端 未结 15 2308
南笙
南笙 2020-11-22 05:39

What is the best (and fastest) way to retrieve a random row using Linq to SQL when I have a condition, e.g. some field must be true?

相关标签:
15条回答
  • 2020-11-22 05:49

    i use this method for take random news and its work fine ;)

        public string LoadRandomNews(int maxNews)
        {
            string temp = "";
    
            using (var db = new DataClassesDataContext())
            {
                var newsCount = (from p in db.Tbl_DynamicContents
                                 where p.TimeFoPublish.Value.Date <= DateTime.Now
                                 select p).Count();
                int i;
                if (newsCount < maxNews)
                    i = newsCount;
                else i = maxNews;
                var r = new Random();
                var lastNumber = new List<int>();
                for (; i > 0; i--)
                {
                    int currentNumber = r.Next(0, newsCount);
                    if (!lastNumber.Contains(currentNumber))
                    { lastNumber.Add(currentNumber); }
                    else
                    {
                        while (true)
                        {
                            currentNumber = r.Next(0, newsCount);
                            if (!lastNumber.Contains(currentNumber))
                            {
                                lastNumber.Add(currentNumber);
                                break;
                            }
                        }
                    }
                    if (currentNumber == newsCount)
                        currentNumber--;
                    var news = (from p in db.Tbl_DynamicContents
                                orderby p.ID descending
                                where p.TimeFoPublish.Value.Date <= DateTime.Now
                                select p).Skip(currentNumber).Take(1).Single();
                    temp +=
                        string.Format("<div class=\"divRandomNews\"><img src=\"files/1364193007_news.png\" class=\"randomNewsImg\" />" +
                                      "<a class=\"randomNews\" href=\"News.aspx?id={0}\" target=\"_blank\">{1}</a></div>",
                                      news.ID, news.Title);
                }
            }
            return temp;
        }
    
    0 讨论(0)
  • 2020-11-22 05:53

    One way to achieve efficiently is to add a column to your data Shuffle that is populated with a random int (as each record is created).

    The partial query to access the table in random order is ...

    Random random = new Random();
    int seed = random.Next();
    result = result.OrderBy(s => (~(s.Shuffle & seed)) & (s.Shuffle | seed)); // ^ seed);
    

    This does an XOR operation in the database and orders by the results of that XOR.

    Advantages:-

    1. Efficient: SQL handles the ordering, no need to fetch the whole table
    2. Repeatable: (good for testing) - can use the same random seed to generate the same random order

    This is the approach used by my home automation system to randomize playlists. It picks a new seed each day giving a consistent order during the day (allowing easy pause / resume capabilities) but a fresh look at each playlist each new day.

    0 讨论(0)
  • 2020-11-22 05:54

    To add to Marc Gravell's solution. If you are not working with the datacontext class itself (because you proxy it somehow e.g. to fake the datacontext for testing purposes), you cannot use the defined UDF directly: it will not be compiled to SQL because you're not using it in a subclass or partial class of your real data context class.

    A workaround for this problem is to create a Randomize function in your proxy, feeding it with the query you want to be randomized:

    public class DataContextProxy : IDataContext
    {
        private readonly DataContext _context;
    
        public DataContextProxy(DataContext context)
        {
            _context = context;
        }
    
        // Snipped irrelevant code
    
        public IOrderedQueryable<T> Randomize<T>(IQueryable<T> query)
        {
            return query.OrderBy(x => _context.Random());
        }
    }
    

    Here is how you'd use it in your code:

    var query = _dc.Repository<SomeEntity>();
    query = _dc.Randomize(query);
    

    To be complete, this is how to implement this in the FAKE datacontext (which uses in memory entities):

    public IOrderedQueryable<T> Randomize<T>(IQueryable<T> query)
    {
        return query.OrderBy(x => Guid.NewGuid());
    }
    
    0 讨论(0)
  • 2020-11-22 05:55

    Came here wondering how to get a few random pages from a small number of them, so each user gets some different random 3 pages.

    This is my final solution, working querying with LINQ against a list of pages in Sharepoint 2010. It's in Visual Basic, sorry :p

    Dim Aleatorio As New Random()
    
    Dim Paginas = From a As SPListItem In Sitio.RootWeb.Lists("Páginas") Order By Aleatorio.Next Take 3
    

    Probably should get some profiling before querying a great number of results, but it's perfect for my purpose

    0 讨论(0)
  • 2020-11-22 05:58
    var cust = (from c in ctx.CUSTOMERs.ToList() select c).OrderBy(x => x.Guid.NewGuid()).Taket(2);
    

    Select random 2 row

    0 讨论(0)
  • 2020-11-22 06:03

    You can do this at the database, by using a fake UDF; in a partial class, add a method to the data context:

    partial class MyDataContext {
         [Function(Name="NEWID", IsComposable=true)] 
         public Guid Random() 
         { // to prove not used by our C# code... 
             throw new NotImplementedException(); 
         }
    }
    

    Then just order by ctx.Random(); this will do a random ordering at the SQL-Server courtesy of NEWID(). i.e.

    var cust = (from row in ctx.Customers
               where row.IsActive // your filter
               orderby ctx.Random()
               select row).FirstOrDefault();
    

    Note that this is only suitable for small-to-mid-size tables; for huge tables, it will have a performance impact at the server, and it will be more efficient to find the number of rows (Count), then pick one at random (Skip/First).


    for count approach:

    var qry = from row in ctx.Customers
              where row.IsActive
              select row;
    
    int count = qry.Count(); // 1st round-trip
    int index = new Random().Next(count);
    
    Customer cust = qry.Skip(index).FirstOrDefault(); // 2nd round-trip
    
    0 讨论(0)
提交回复
热议问题