Randomize database table result with LINQ - linq

from f in db.Table1
orderby Guid.NewGuid()
select f
this doesn't seem to work. how can i randomize results?

How about
SELECT TOP 1 column FROM table ORDER BY NEWID and skip the linq :)
Or try this:
var t = (from row in db.Table1 order by table1.random()
select row).FirstOrDefault();

Maybe something like this works (not tested):
(from f in db.Table1 select new { f, r = Guid.NewGuid()}).OrderBy(x => x.r)

Randomize whole list
db.Table1.OrderBy(x => Guid.NewGuid())
Get single Random
db.Table1.OrderBy(x => Guid.NewGuid()).FirstOrDefault();

I like to write an extension method for this.
IEnumerable<T> Randomize(this IEnumerable<T> list)
{
T[] result = list.ToArray();
Random random = new Random();
for(int i = result.Length; i > 0; i--)
{
result[i] = random.Next(i);
}
return (result);
}

Related

Linq to Sql Query - better solution (optimizing)

The following code works, but it's not a nice code. (low performance)
I have a dictionary with value and key.
First i go trough every webcodes who exist. Then i load all participants in a list (where webcode equals the actual webcode in the foreach). After that i add the data (parameter of the webcode and a count of participants to the dictionary).
Guid compID = Guid.Parse(wID);
ChartModel webcodes = new ChartModel();
webcodes.Title = "Webcodes Statistics";
webcodes.Data = new Dictionary<string, int>();
var webcodesData = db.t_Webcode;
foreach (var w in webcodesData)
{
var wData = db.t_Participant.Where(t => t.FK_Competition == compID && t.Webcode == w.Webcode);
if (wData.Count() != 0)
webcodes.Data.Add(w.Parameter, wData.Count());
}
ViewBag.Webcodes = webcodes;
TIA
You need something along these lines:
webcodes.Data = (from w in db.t_Webcode
join p in db.t_Participant on w.Webcode equals p.Webcode
where p.FK_Competition == compID
group w by w.Parameter into g
select new { g.Key, Count = g.Count() }).ToDictionary();
I can't test it but that is the type of query you need.
This will assume that you have relationships defined in your database and that your LINQ to SQL datacontext are aware of them. If not, you will need to join manually on t_Participants from tWebcode.
This should execute in 1 single SQL query, instead of 1 query per row in tWebcode.
var webcodesAndNoOfParticipants =
from webcode in db.tWebcode
// Define number of participants for this webcode
let numberOfParticipants = webcode.t_Participants.Count(participant => participant.FK_Competition == compID)
where numberOfParticipants > 0
select new {
WebcodeParameter = webcode.Parameter,
NoOfParticipants = numberOfParticipants
};
webcodes.Data = webcodesAndNoOfParticipants.ToDictionary(x => x.WebcodeParameter, x => x.NoOfParticipants);

how can this SQL be done in LINQ?

i have this simple SQL query...
-- BestSeller
SELECT TOP(1) v.make, v.model, COUNT(v.make) AS NoSold
FROM Vehicles v
group by v.make, v.model
order by NoSold DESC
Im using entity framwork and want to do the same thing using linq. so far i have...
var tester = (from v in DB.VP_Historical_Vehicles
group v by v.make into g
orderby g.Count() descending
select new { make = g.Key, model = g, count = g.Count() }).Take(1);
foreach(var t in tester)
{
BestSeller.Make = t.make;
BestSeller.Model = t.make;
BestSeller.CountValue = t.count;
}
i keep getting timeouts, the database is large but the SQL runs very quick
any sugestions?
thanks
truegilly
Group by a compound key.
var t = (
from v in DB.VP_Historical_Vehicles
group v by new { v.make, v.model } into g
orderby g.Count() descending
select new { make = g.Key.make, model = g.Key.model, count = g.Count() }
)
.First();
BestSeller.Make = t.make;
BestSeller.Model = t.make;
BestSeller.CountValue = t.count;
Check what queries it performs when you run it with LINQ.
I suspect that you orderby g.Count() descending might be executing a COUNT query for each row and that would take a toll on performance to say the least.
When working with EF, always check what your LINQ statements produce in terms of queries. It is very easy to create queries that result in a n+1 scenario.
thanks to Scott Weinstein answer i was able to get it working
please comment if there is a more efficiant way of doing this...
VehicleStatsObject BestSeller = new VehicleStatsObject();
using (var DB = DataContext.Get_DataContext)
{
var t = (from v in DB.VP_Historical_Vehicles
group v by new { v.make, v.model } into g
orderby g.Count() ascending
select new { make = g.Key.make, model = g.Key.model, count = g.Count() }).OrderByDescending(x => x.count).First();
BestSeller.Make = t.make;
BestSeller.Model = t.model;
BestSeller.CountValue = t.count;
}
return BestSeller;

Linq to NHibernate, Order by Rand()?

I'm using Linq To Nhibernate, and with a HQL statement I can do something like this:
string hql = "from Entity e order by rand()";
Andi t will be ordered so random, and I'd link to know How can I do the same statement with Linq to Nhibernate ?
I try this:
var result = from e in Session.Linq<Entity>
orderby new Random().Next(0,100)
select e;
but it throws a exception and doesn't work...
is there any other way or solution?
Thanks
Cheers
I guess Linq to NHibernate is unable to convert the Random.Next call to SQL...
An option would be to sort the results after you retrieve them from the DB :
var rand = new Random();
var query = from e in Session.Linq<Entity>
select e;
var result = from e in query.AsEnumerable()
orderby rand.Next(0,100)
select e;
Note that you need to use a single instance of Random, because the seed is based on the current number of ticks ; if you create several instances of Random with very short interval, they will have the same seed, and generate the same sequence.
Anyway, sorting a collection based on a random number is not such a good idea, because the sort won't be stable and could theoretically last forever. If you need to shuffle the results, you can use the Fisher-Yates algorithm :
var result = Session.Linq<Entity>().ToArray();
var rand = new Random();
for(int i = result.Length - 1; i > 0; i--)
{
int swapIndex = rand.Next(i + 1);
var tmp = result[i];
result[i] = result[swapIndex];
result[swapIndex] = tmp;
}

conditional assignments in Linq to SQL methods

How do I do something like the following, assinging new values based on condition within a linq method but keeping all results.
int x= 100;
var results= from r in Results where r.id==id select r
{ if r.value==x set r.result="Found"}
You're not really meant to - ideally queries shouldn't have side effects. I mean you can do:
var results = Results.Where(r => r.id == id)
.Select(r => {
if (r.value == x)
{
r.result = "Found";
}
return r;
};
I'd generally try not to though...
Note that this really won't work in LINQ to SQL etc.
It's probably better to make a second pass so you can keep your query clean and side-effect-free.
int x = 100;
List<Result> results = (from r in Results
where r.id == id
select r).ToList();
results.ForEach(r => r.result = r.value == x ? "Found" : "Not Found");
Linq should not be used in that way. I would iterate over the results of the query and then change them.
var results= from r in Results where r.id==id select r;
foreach (var r in results.ToList()) { if (r.value==x) r.result="Found"; }

Iterating Linq result set using indexers

Let's ay I have this query:
var results = from row in db.Table select row;
How can I access this:
string name = results[0]["columnName"];
if you really want a particular index you can use the Skip() method with First().
var rowOffset = 0;
var results = (from row in db.Table
select row).Skip(rowOffset).First()["columnName"];
But unless you are using a Where clause I would really recommend using the indexer. The indexer is pretty much a direct reference while the LINQ statement would be using the objects iterator.
Also don't forget you can do much more advanced stuff with LINQ.
var rowOffset = 0;
var pageLength = 10;
var results = (from row in db.Table
let colValue = row["columnname"]
where colValue != null
select colValue.ToString()
).Skip(rowOffset)
.Take(pageLength)
.ToArray();
var commaString = string.Join(", ", results);
If you specifically just want the zeroth element, you can use results.First()
results is a IEnumerable list of Rows. So you can get it with a simple foreach.
foreach(var row in results)
{
string name = row["columnName"];
}
(from row in db.Table select row).First().columnName

Resources