How to select Random record in Azure Table - c#

What is the efficient way to select random record out of out put list in Azure table? Following code return always same record. Whats the reason for that?
T entity = new T();
TableQuery<T> query = new TableQuery<T>();
var tableSet = table.ExecuteQuery(query).ToList();
if (tableSet.Count >= 1)
{
return tableSet.First();
}
return null;

Following code return always same record. Whats the reason for that?
As you know the records in an Azure Table are sorted alphabetically, first by PartitionKey and then by RowKey for each PartitionKey. Because you didn't specify any query condition, table service will start fetching the data from the top (i.e. 1st Partition). Now you're asking the table storage to return only one record, it will pick the very 1st record in that Partition. This is why you're getting the same record.
If you want to get random result back, you have to specify some query parameter. One such possibility could be to specify a PartitionKey value at random. If the PartitionKey exists in the table, then it would return the 1st record in that Partition.

Thanks for feed back on this question. I arrived at following solution to pickup a random record from the out put list.
T entity = new T();
TableQuery<T> query = new TableQuery<T>();
var tableSet = table.ExecuteQuery(query).ToList();
Random rnd = new Random();
if (tableSet.Count >= 1)
{
return tableSet.ElementAt(rnd.Next(1, tableSet.Count));
}
return null;

Related

Get an int out of a Linq query instead of string

I'm new to c#, Linq and .NET. I have some code that does a query to get the last record from a table in a database. The field that I'm trying to access is an int but when I try to print it I get System.Data.Objects.ObjectQuery`1[System.Int32].
Here's the code:
public void getLastProgNumber()
{
using (var db = new IntranetEntities())
{
var value = (db.table.OrderByDescending(ai => ai.NumProgHWSW).GroupBy(a => a.NumProgHWSW).Select(g => Convert.ToInt32(g.FirstOrDefault())));
MessageBox.Show(value.ToString());
}
}
I need to convert it to an int type and return it if possible, thank you. (Right now I'm using void because I'm trying to get the right result before returning it)
If you want to get the last record from the database table, there are multiple ways. But doing GroupBy is certainly not one of them.
You can order the rows by doing OrderByDescending so that row with the maximum value of that column positioned at the first and then you can do FirstOrDefault.
var val = db.table.OrderByDescending(ai => ai.NumProgHWSW).FirstOrDefault();
// val is the row with maximum value of NumProgHWSW.
// you can display the value of NumProgHWSW in messagebox by doing following.
MessageBox.Show(val.NumProgHWSW);
If you want to get the Maximum value of NumProgHWSW in a variable directly from the LINQ query. you can do this by
var val = db.table.OrderByDescending(ai => ai.NumProgHWSW).FirstOrDefault().NumProgHWSW;
MessageBox.Show(val);
You can also use Max LINQ method to get the maximum value without doing OrderByDescending.
var val = db.table.Max(ai => ai.NumProgHWSW);
MessageBox.Show(val);
Using Max is a better approach then above two as it does not order the table rows before data retrieval and that way it works faster when the table has large number of rows.

How to skip last 2 records and get all other records with linq?

I have a table called Test:
Test: Id, CreatedBy, CreatedDate
Now I want to get list of test but skip last 2 test. So if I have say for e.g. 10 test then I want to get 1 - 8 test and skip test 9 and 10.
This is how I am trying to do that:
var query = context.Test.OrderByDescending(t=>t.Id).Skip(2) // How to take other records?
In this case: Take(8)
With Take and Skip you can get any range you want.
E.G:
var query = context.Test.OrderByDescending(t=>t.Id);
var allButTheLastTwoElements = query.Take(query.Count() - 2);
Safest way:
var query = context.Test.OrderByDescending(t=>t.Id).ToList();
var allButTheLastTwoElements = query.Take(Math.Max(0,query.Count() - 2));
Or you could just do it the other way around (depending on your requirements)
var query = context.Test.OrderByAscending(t=>t.Id).Skip(2);
If records size is not fixed, you would use:
test.Take(test.Count-2);
//If records are already sorted in the order you like,
or
test.Where(t=>t.ID <= test.Max(m=>m.ID)-2);
//Where ID is a unique key and the list may not be sorted by id
//This will return the lowest 8 ID even if the list is sorted by address or whatever.
What you need is very simple, you don't even need to use Take or query the database twice.
If you OrderByDescending and Skip the first N elements, then you're taking all the remaining elements by default. So you can just do this:
var query = context.Test.OrderByDescending(t=>t.Id).Skip(2);
Docs:
Bypasses a specified number of elements in a sequence and then returns
the remaining elements.
If you don't really intend to deffer the execution or append additional querying logic, then calling .ToList() at the end (which actually executes the query against the database) is logical.

How to preserve list values after linq operation?

I am querying azure table. After getting the data I am performing linq select operation and getting modified values.
But I want two lists one with old values and other with new values.
var oldUserEntities = userEntities.ToList();
var newUserEntities = userEntities.Select(i => { i.RowKey = dict[i.RowKey]; return i; }).ToList();
After this code if I verify values in oldUserEntites and newUserEntities, both having same modified values.
How to have old list and new list?
That's because the i in your projection is referencing the original item in oldUserEntities, then i.RowKey is modifying the original data.
Try this instead (assuming your entity is named UserEntity):
var oldUserEntities = userEntities.ToList();
var newUserEntities = userEntities.Select(i => new UserEntity
{
RowKey = dict[i.RowKey],
// rest of desired properties ...
}).ToList();
I'm not really sure what you're trying to do here, but this
> i => { i.RowKey = dict[i.RowKey]; return i }
is changing RowKey on every object in the list. The "return i" is then making a list containing the same, now modified, objects.
all this is really doing is
foreach(i in userEntities)
i.RowKey = dict[i.RowKey]
and then making a copy of the list

Retrieve value of field in list of entity objects by its ID field

I have something like:
List<Cat> cats = AnimalEdmContext.Current.Cats.ToList();
Where Cat is a table in my database, with fields CatId and Breed.
How can I access the value of the Breed field that corresponds to a given integer CatId?
You need to query over the database to do that. The following example shows you how to do that.
var theCatId = 1; // Or whatever
var theCatIWant = AnimalEdmContext.Current.Cats.Where(c => c.CatId = theCatId).Single();
var theBreedIs = theCatIWant.Breed;
Doing this you just retrieve from the database the Cats that match your condition. In the other hand, if you do the filtering over the whole list like the one you are getting in your question, you will be retrieving all records from database and then filtering them, which costs more.
The Single LINQ method allows you to specify the condition as well, that the single element should match. I have added the Where method to so it is clearer what we are doing.
Single will throw an exception if no record is found or if more than one are found.
You can use ::
var catBreed = cats.First(x=>x.CatdId == desiredId).Breed;
If you are looking for a specific item, you could do something like:
var cat = AnimalEdmContext.Current.Cats.First(cat => cat.CatId == 1);
var breed = cat.Breed;
This will retrieve the first Cat item in the table that has the ID of 1, in this example.

Find a random content in the database - Linq

I need to get out of how I find a random thing in the database as shown to the audience and at the same time it must be able to show one of time.
Normally I have done like this
cmd1.CommandText = #"SELECT TOP 1 opgaver.id, opgaver.rigtigsvar, opgaver.overskift, opgaver.svar1,
opgaver.svar2, opgaver.svar3, opgaveLydefiler.mp3 FROM opgaver INNER JOIN opgaveLydefiler ON opgaver.overskift = opgaveLydefiler.navn ORDER BY newid()";
Tasks and task sounds files are put together such that they, like partnerships / has an inner join together.
I've tried to do like this, but I can not right for it to display only one and the same time make a random of it as I have in the database.
Opgaver opgaver = db.opgavers.FirstOrDefault().Take(1);
EIDT - I have chosen to do like this,
var random = new Random();
var antalopgaver = db.opgavers.Count();
var number = random.Next(antalopgaver);
var randomlySelectedItem = db.opgavers.Skip(number).Take(1).FirstOrDefault();
Here you go:
var item = db.opgavers.OrderBy(q=>Guid.NewGuid()).FirstOrDefault();
Here is an idea in short.
If let's say you are interested in the top 100 records, for example ordered by the date of addition. Then try to generate a random number between 0 and 99 like this:
var random = new Random();
var number = random.Next(100);
Then use this number as offset for your query:
var item = db.opgavers.OrderByDescending(e => e.DateAdded).Skip(number).Take(1).FirstOrDefault();
I advice using FirstOrDefault against First because that way you can handle for example the empty database case, which is sometimes a valid state.
I used Take(1) because I think it is the safest way to ensure that the query will contain the LIMIT clause. Otherwise some LINQ providers might do it else way.
If you can't do such an ordering what I supposed, then as others have pointed out, you could get the number of rows before the query, and use it instead of 100. But that's another query to the database which is sometimes OK, sometimes not so much.
You can order your records by a random number, and then take the first :
var random = new Random();
var randomlySelectedItem =
db.opgavers.Select(o => new { op = o, sort = random.Next(0,10000) })
.OrderBy(obj => obj.sort)
.FirstOrDefault();
Replace the hard coded 10,000 by a number that is basically corresponding to the count of your items (does not need to be the exact count)

Categories

Resources