Get an int out of a Linq query instead of string - c#

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.

Related

Seeking for help for SQL server query to search multiple columns of a table using a combination of keywords

I am having a nightmare in building an efficient search query. I am using LINQ. The requirement is as follows:
In the application there is one text fox field which is used as a Quick Search.
The table I will be searching holds three fields Make, Model and Extension.
A typical keyword user can enter is like Honda Accord XL
Based on the keywords database should return me the matching rows and here the problem starts. There is no restriction on the order which keywords will be entered to prepare the phrase, i.e. one can enter Accord XL Honda or it could be like XL Accord or could just be Honda. In the example Honda is Make, Accord is the Model and XL is the extension.
Ideally the search result should only pull up perfect matches like if Honda Accord is entered it will not bring up other models from Honda. But the major problem is I don't know what they will enter and I have to look into three different columns of the table using Contains operator.
Here is what I tried:
I spit the phrase into words and place them in an array
var arr = keyWord.Split(new [] {' '}). Next step I build the query inside a loop of those array elements:
foreach (var k in arr)
{
var item = new Vehicle();
var arrayItem = k;
var query = DataContext.Vehicles.Where(v =>v.RealName.Contains(arrayItem)
|| v.Model.Contains(arrayItem)
|| v.Style.Contains(arrayItem)).ToList();
foreach (var v in query)
{
if(!result.Contains(v))
result.Add(v);
}
}
return result;
Now when the loop is executing and matching records for Make it already fills the list with say 250 items. But how can I remove unwanted items like when a record has CT as Model or TYL as Extension? If I knew the order of the words in which the keyword was created then I will have the option to remove unmatched Make, Model or Extension from the list by using one line of code for each and return the final result. But in this case if I have to do it I again have to use loop and remove unmatched items, even that will not probably give me the correct data. And definitely this is not the efficient way to do this.
--- Try to use Below way your code first retrieve respective make to database ------then filter gettting previous result.
List<Vehicle> lsvehicle= new List<Vehicle()>;
foreach (var k in arr)
{
var arrayItem = k;
lsvehicle = DataContext.Vehicles.Where(v =>v.RealName.Contains(arrayItem) ).ToList();
}
foreach (var k in arr)
{
lsvehicle = lsvehicle.Where(v =>v.Model.Contains(arrayItem) || v.Style.Contains(arrayItem)).tolist();
}
return lsvehicle ;
This can be achieved by concatenating the Make + Model + Extension string and then comparing that the whole array is contained by this string
var query = DataContext.Vehicles;
foreach (var k in arr)
{
var item = new Vehicle();
var arrayItem = k;
query = query.Where(v => (v.RealName + v.Model + v.Style).Contains(arrayItem)).ToList();
}
return query;
NOTE: Logical answer, may require syntax error correction if any
I would suggest following approach, assuming you have the option to create view in database
and you are searching through three columns
1)Create a view With all combination
2)Use linq to get the record from the view
sql
create view [Vw_VehicleSearch]
AS
Select
M+V+E [MVE],
M+E+V [MEV],
V+M+E [VME],
v+E+M [VEM],
E+M+V [EMV],
E+V+M [EVM]
from
vehicletable
c#
public List<string> Search(string quickSearchText)
{
using(var ctx=new model()))
{
var result=ctx
.Vw_VehicleSearch
.Where(v=>v.MVE.Contains(quickSearchText)
|| v=>v.MEV.Contains(quickSearchText)
.|| v=>v.VME.Contains(quickSearchText)
.|| v=>v.VEM.Contains(quickSearchText)
.|| v=>v.EMV.Contains(quickSearchText)
.|| v=>v.EVM.Contains(quickSearchText)
.ToList();
return result.Select(r=>r.MVE).ToList();
}
}
What you want is: all vehicles of which either RealName, or Model, or Style contains all keywords. This can be achieved by:
var query = DataContext.Vehicles.Where(v =>
arr.All(s => v.RealName.Contains(s))
|| arr.All(s => v.Model.Contains(s))
|| arr.All(s => v.Style.Contains(s)))
.ToList();
Entity Framework is able to translate this query into SQL because it has a trick to convert the array arr into a table (of sorts) that can be used in the SQL statement (you should take a look at the generated SQL).
This is not the most efficient way to run a query. It will become considerably slower when the number of keywords becomes "large". I don't think that will be an issue here though.

How to select Random record in Azure Table

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;

Return DataRow whose field is the max for specified column

I want to be able to get a datarow from a datarow array where the datarow has the maximum value for a specified column in all of the datarows.
I imagine it would follow suit to this LINQ statement
Dim minRow As DataRow = myDataRows.AsEnumerable.Min(Function(row) row.Field(Of Decimal)("myColumnName"))
However the Max function returns a decimal instead of a datarow. Is there some easy syntax that handles such a query for me?
And before anyone asks, I tag c# since in winforms they can easily be converted between each other using a website.
If you can use MoreLINQ, this can easily be done using MaxBy():
var maxRow = myDataRows.MaxBy(r => r.Field<Decimal>("myColumnName"));
But using regular Linq:
var minRow = myDataRows.OrderBy(r => r.Field<decimal>("myColumnName")).FirstOrDefault();
var maxRow = myDataRows.OrderBy(r => r.Field<decimal>("myColumnName")).LastOrDefault();
A little late but I want to share it anyway ;), you can do it in O(n) instead of O(n*log n) (which is the order for OrderBy extension method) if you use Aggregate extension method:
var minRow =myDataRows.Aggregate(myDataRows[0],(seed,next)=>next.Field<decimal>("myColumnName").Field<decimal>("myColumnName")?next:seed);
Check if your myDataRows array have at least one row

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

Getting one element from a strongly typed data set

I just learnead to use a strongly typed dataset along with stored procedures today and things are going very well , except one little problem.I can figure out how to get my data out of a datatable with itarating over it considering the fact that the datable has only one column with one row in it.This is what I have so far:
var bookCountAdapter = new CountBooksTableAdapter();
var bookCountDataTable = new BooksAndCategoriesDataSet.CountBooksDataTable();
bookCountAdapter.Fill(bookCountDataTable);
int totalNumberOfBooks = 0;
foreach (BooksAndCategoriesDataSet.CountBooksRow row in bookCountDataTable) {
totalNumberOfBooks = row.TotalNumberOfBooks;
}
return totalNumberOfBooks;
THe store procedure that is used by the dataset is:
CREATE PROCEDURE [dbo].[CountBooks]
AS
SELECT COUNT(*) FROM Books
Now my curent code works just fine.The problem is that I do not see a reason for itarating over bookCountDataTable because I have in it only one element of type int and I only want to retrieve that.
Is there a way I could get that element by writing something similar like this :
bookCountDataTable.TotalNumberOfBooks
I am sure you can do something like this:
if(bookCountDataTable.Rows.Count > 0)
{
totalNumberOfBooks = Convert.ToInt32(bookCountDataTable.Rows[0]["TotalNumberOfBooks"]);
}
because I have in it only one element of type int and I only want to
retrieve that.
Access it with the index then like:
return bookCountDataTable[0].TotalNumberOfBooks
But you should check the Row count for the table before.
From your foreach loop it looks like if there are going to be multiple rows in there then the last one's TotalNumberofBooks will be returned.
If you're sure you will have a single element you could do something like this
int totalNumberOfBooks = bookCountDataTable[0].TotalNumberOfBooks;
In any case you shouldn't be using a data set for retrieving a single value. There're better ways to do this as SqlCommand.ExecuteScalar
Even on your typed data set you could use the wizard on design view to create a query that returns a single value.

Categories

Resources