Get database row from selected item in Combobox - c#

I have a Combobox which gets its data from my database.
var people = (from x in db.Person select new { Value = x.Id, Names = x.Namn + " " + x.EfterNamn }).ToList();
cbpeople.DataSource = people;
cbpeople.DisplayMember = "Names";
cbpeople.ValueMember = "Value";
cbpeople.SelectedIndex = -1;
And I have the SelectedIndex function
int id = cbpeople.SelectedIndex + 1;
string namn = (from x in db.Person where x.Id == id select x.Namn).ToString();
lblNamn.Text = namn;
So as you can see, I'm trying to have it select the information from the same row in the database and put them in labels. (The "cbpeople.SelectedIndex + 1;" is because I had no other way to get the ID from the SelectedValue).
But all it prints out is this long thing instead of the Name (on the label)
"SELECT \r\n [Extent1].[Namn] AS [Namn]\r\n FROM [dbo].[Person] AS [Extent1]\r\n WHERE [Extent1].[Id] = #p__linq__0"
What am I doing wrong?

You calling ToString() over IQueryable object. Of course, it will return it's SQL representation. To execute query you can do this:
string namn = (from x in db.Person where x.Id == id select x.Namn).Single();

Related

Labels doesn't display what i need from SQL database (Linq to SQL)

I have a database which holds data i need and i want to display these data in several different labels. I am choosing a Primary Key that represents rows in datatable from combobox and every selected index change i want to retrieve other related details to that specific Primary Key (MID) into labels.
I tried using below code;
private void CBMeasDBMID_SelectedIndexChanged(object sender, EventArgs e)
{
using (LinqDataClassesDataContext dataContext = new
LinqDataClassesDataContext())
{
var query = from x in dataContext.MeasResults
where x.MoldID == cBMeasDBMID.SelectedValue.ToString()
group x by x.MeasId into grp
select grp.OrderByDescending(x => x.Date).First();
var result = query.OrderByDescending(x => x.Date).Take(5);
daGridLastMeas.AutoGenerateColumns = false;
daGridLastMeas.Columns["MeasId"].DataPropertyName = "MeasId";
daGridLastMeas.Columns["Date"].DataPropertyName = "Date";
daGridLastMeas.Columns["Plane"].DataPropertyName = "Plane";
daGridLastMeas.Columns["Position"].DataPropertyName = "Postn";
daGridLastMeas.DataSource = result;
var manuf = from y in dataContext.Moulds
where y.MID == cBMeasDBMID.SelectedValue.ToString()
select y.manuf;
lblManufac.Text = manuf.ToString();
var size = from a in dataContext.Moulds
where a.MID == cBMeasDBMID.SelectedValue.ToString()
select a.Size;
lblSize.Text = size.ToString();
var lastmeas = from c in dataContext.MeasResults
where c.MoldID == cBMeasDBMID.SelectedValue.ToString()
select c.Date;
lblLastMeasDate.Text = lastmeas.ToString();
var wi = from d in dataContext.Moulds
where d.MID == cBMeasDBMID.SelectedValue.ToString()
select d.AWI;
lblWi.Text = wi.ToString();
}
}
My problem is code doesn't retrieve the data, instead when i first click to combobox to choose an ID, all labels show SELECT text which is Primary Key selection ComboBox's default text and afterwards there is no change or data retrieve even though i change the selected index.
How can i fix this issue?
var manuf = (from y in dataContext.Moulds
where y.MID == cBMeasDBMID.SelectedValue.ToString()
select y.manuf).FirstOrDefault();
lblManufac.Text = manuf.ToString();
var size = (from a in dataContext.Moulds
where a.MID == cBMeasDBMID.SelectedValue.ToString()
select a.Size).FirstOrDefault();
lblSize.Text = size.ToString();
var lastmeas = (from c in dataContext.MeasResults
where c.MoldID == cBMeasDBMID.SelectedValue.ToString()
select c.Date).FirstOrDefault();
lblLastMeasDate.Text = lastmeas.ToString();
var wi = (from d in dataContext.Moulds
where d.MID == cBMeasDBMID.SelectedValue.ToString()
select d.AWI).FirstOrDefault();
lblWi.Text = wi.ToString();
Think this will solve your problem

retrieve last value from table in linq Extention method and bind with DataGridView

I am working on windows Form App. I want to retrieve last record from database and bind it with datagridview, I can get all value from this
var query2 = _context.Products.Join(_context.ProductInfos, c => c.Id, a => a.ProductId, (a, c) => new
{
Id = a.Id,
ItemName = a.ItemName,
CategoryName = a.Category.CategoryName,
UnitName = a.Unit.UnitName,
UnitValue = a.UnitSize,
Quantity = a.Quantity,
CostPrice = c.PurchasePrice,
SalePrice = c.SalePrice,
EntryDate = c.EntryDate,
ExpireDate = c.ExpireDate
}).toList();
StockListGrid.DataSource = query2;
but i only want the last inserted value, i use
var query2 = _context.Products.Join(_context.ProductInfos, c => c.Id, a => a.ProductId, (a, c) => new
{
Id = a.Id,
ItemName = a.ItemName,
CategoryName = a.Category.CategoryName,
UnitName = a.Unit.UnitName,
UnitValue = a.UnitSize,
Quantity = a.Quantity,
CostPrice = c.PurchasePrice,
SalePrice = c.SalePrice,
EntryDate = c.EntryDate,
ExpireDate = c.ExpireDate
}).ToList().LastOrDefault();
StockListGrid.DataSource = query2;
but this time i get no value.Please tell me how can i retrieve last inserted value?
Try using OrderByDescending
var query2 = _context.Products.Join(_context.ProductInfos, c => c.Id, a => a.ProductId, (a, c) => new
{
Id = a.Id,
ItemName = a.ItemName,
CategoryName = a.Category.CategoryName,
UnitName = a.Unit.UnitName,
UnitValue = a.UnitSize,
Quantity = a.Quantity,
CostPrice = c.PurchasePrice,
SalePrice = c.SalePrice,
EntryDate = c.EntryDate,
ExpireDate = c.ExpireDate
}).OrderByDescending(x => x.Id).First();
Or Max
var query2 = _context.Products.Join(_context.ProductInfos, c => c.Id, a => a.ProductId, (a, c) => new
{
Id = a.Id,
ItemName = a.ItemName,
CategoryName = a.Category.CategoryName,
UnitName = a.Unit.UnitName,
UnitValue = a.UnitSize,
Quantity = a.Quantity,
CostPrice = c.PurchasePrice,
SalePrice = c.SalePrice,
EntryDate = c.EntryDate,
ExpireDate = c.ExpireDate
}).Max(x => x.Id);
The type of your first query is a List<...>, all elements are of the same anonymous type Anonymous1. The type of your later query is one object of class Anonymous1. What does your StockListGrid.DataSource expect? A list or one single object?
ToList transports all elements from your Database management system (DBMS) to your local memory, after which you decide that you only want the last element
I see two problems
Why transport all elements if you only want the last one?
Is the last element of your joinresult defined? Is it the one with the highest Id? Or maybe the one with alphabetically last ItemName? Is it the one with the highest SalePrice?
Unfortunately Entity Framework does not support LastOrDefault. See Supported and Unsupported LINQ methods (linq to entities)
The trick around this would be sorting in ascending order by the property you consider last and then take the FirstOrDefault. Keep in mind that (depending on your sort property) there might be several items with the same sort value, so a second sort is needed
var result = dbContext.Products.Join(dbContext.ProductInfos, ...)
.OrderByDescending(joinResult => joinResult.SalePrice) // depending on your definition of Last
.ThenByDescending(joinResult => joinResult.Id) // in case there are two with same price
.FirstOrDefault();
This is much more efficient, because only one element is transported from your DBMS to your local memory.
Note that the result is only one element, not a List. If you want assign a List with only this last element to your DataSource
.ThenByDescending(joinResult => joinResult.Id)
.Take(1)
.ToList();
Again, only one anonymous object is transported

How to use linq result input sql where in

I have a linq script
var ID = (from item in ConflictDatas.AsEnumerable()
group item by new
{
ID = item.Field<string>("ID"),
DesignArticle = item.Field<string>("DesignArticle"),
DesignNo = item.Field<string>("DesignNo"),
PatternCode = item.Field<string>("PatternCode")
} into g
where g.Count() >= 2
select new
{
g.Key.ID
}).ToList();
I want to put this result into a sql commnad.
I try:
string sqlwhere;
sqlwhere = string.Join(",", ID);
tsql = #"
Insert ConflictDesignArticle
Select * from ReadyworkData where ID in (" + sqlwhere + #") ";
After compile:
Insert ConflictDesignArticle
Select * from ReadyworkData where ID in ({ ID = SPSOS17040113 },{ ID =
SPSOS17040115 },{ ID = SPSOS17040114 })
How to modify my code. Thanks.
Thank you for Lei Yang help
var ID = (from item in ConflictDatas.AsEnumerable()
group item by new
{
ID = item.Field<string>("ID"),
DesignArticle = item.Field<string>("DesignArticle"),
DesignNo = item.Field<string>("DesignNo"),
PatternCode = item.Field<string>("PatternCode")
} into g
where g.Count() >= 2
select new
{
g.Key.ID
}).Select(x => x.ID).ToList();

Optimizing a value based search algorithm with LINQ

I want to build a value based search algorithm. What this means is that once I'm given a list of words I would like to search for entries on the database using those words. However depending on what column/property those words match, I want to alter the value of results returned.
Here is a lazy algorithm that achieves that but is very slow.
//search only active entries
var query = (from a in db.Jobs where a.StatusId == 7 select a);
List<SearchResult> baseResult = new List<SearchResult>();
foreach (var item in search)
{
//if the company title is matched, results are worth 5 points
var companyMatches = (from a in query where a.Company.Name.ToLower().Contains(item.ToLower()) select new SearchResult() { ID = a.ID, Value = 5 });
//if the title is matched results are worth 3 points
var titleMatches = (from a in query where a.Title.ToLower().Contains(item.ToLower()) select new SearchResult() { ID = a.ID, Value = 3 });
//if text within the body is matched results are worth 2 points
var bodyMatches = (from a in query where a.FullDescription.ToLower().Contains(item.ToLower()) select new SearchResult() { ID = a.ID, Value = 2 });
//all results are then added
baseResult = baseResult.Concat(companyMatches.Concat(titleMatches).Concat(bodyMatches)).ToList();
}
// the value gained for each entry is then added and sorted by highest to lowest
List<SearchResult> result = baseResult.GroupBy(x => x.ID).Select(p => new SearchResult() { ID = p.First().ID, Value = p.Sum(i => i.Value) }).OrderByDescending(a => a.Value).ToList<SearchResult>();
//the query for the complete result set is built based on the sorted id value of result
query = (from id in result join jbs in db.Jobs on id.ID equals jbs.ID select jbs).AsQueryable();
I'm looking for ways to optimize this. I am new to LINQ query so I was hoping I could get some help. If there is away I can create the LINQ query that achieves all of this in one go instead of checking for company name and then title and the body text and bringing it all together and creating a sorted list and running it again against the database to get full listing it would be great.
It's best if I study the problem first. My previous answer was optimizing the wrong thing. The primary problem here is going over the results list multiple times. We can change that:
foreach (var a in query)
{
foreach (var item in search)
{
itemLower = item.ToLower();
int val = 0;
if (a.Company.Name.ToLower.Contains(itemLower))
baseResult.Add(new SearchResult { ID = a.ID, Value = 5});
if (a.Title.ToLower.Contains(itemLower))
baseResult.Add(new SearchResult { ID = a.ID, Value = 3});
if (a.FullDescription.ToLower().Contains(itemLower))
baseResult.Add(new SearchResult { ID = a.ID, Value = 2});
}
}
After that, you have your base result and you can continue with your processing.
That reduces it to a single query rather than three queries for each search item.
I wasn't sure if you wanted unique items in your baseResult, or if there was some reason you allowed duplicates and then used the sum of the values to order them. If you want unique items, you could make baseResult a Dictionary, with the ID as the key.
Edit after comment
You could reduce the number of items in the list by doing:
int val = 0;
if (a.Company.Name.ToLower.Contains(itemLower))
val += 5;
if (a.Title.ToLower.Contains(itemLower))
val += 3;
if (a.FullDescription.ToLower().Contains(itemLower))
val += 2;
if (val > 0)
{
baseResult.Add(new SearchResult { ID = a.ID, Value = val });
}
That won't eliminate duplicates altogether, though, because the company name could match one search term, and the title might match another search term. But it would reduce the list somewhat.
Thanks to Jim's answer and some tweeking on my side I managed to reduce the time it takes to complete the search by 80%
Here is the final solution:
//establish initial query
var queryBase = (from a in db.Jobs where a.StatusId == 7 select a);
//instead of running the search against all of the entities, I first take the ones that are possible candidates, this is done through checking if they have any of the search terms under any of their columns. This is the one and only query that will be run against the database
if (search.Count > 0)
{
nquery = nquery.Where(job => search.All(y => (job.Title.ToLower() + " " + job.FullDescription.ToLower() + " " + job.Company.Name.ToLower() + " " + job.NormalLocation.ToLower() + " " + job.MainCategory.Name.ToLower() + " " + job.JobType.Type.ToLower()).Contains(y))); // + " " + job.Location.ToLower() + " " + job.MainCategory.Name.ToLower() + " " + job.JobType.Type.ToLower().Contains(y)));
}
//run the query and grab a list of baseJobs
List<Job> baseJobs = nquery.ToList<Job>();
//A list of SearchResult object (these object act as a container for job ids and their search values
List<SearchResult> baseResult = new List<SearchResult>();
//from here on Jim's algorithm comes to play where it assigns points depending on where the search term is located and added to a list of id/value pair list
foreach (var a in baseJobs)
{
foreach (var item in search)
{
var itemLower = item.ToLower();
if (a.Company.Name.ToLower().Contains(itemLower))
baseResult.Add(new SearchResult { ID = a.ID, Value = 5 });
if (a.Title.ToLower().Contains(itemLower))
baseResult.Add(new SearchResult { ID = a.ID, Value = 3 });
if (a.FullDescription.ToLower().Contains(itemLower))
baseResult.Add(new SearchResult { ID = a.ID, Value = 2 });
}
}
List<SearchResult> result = baseResult.GroupBy(x => x.ID).Select(p => new SearchResult() { ID = p.First().ID, Value = p.Sum(i => i.Value) }).OrderByDescending(a => a.Value).ToList<SearchResult>();
//the data generated through the id/value pair list are then used to reorder the initial jobs.
var NewQuery = (from id in result join jbs in baseJobs on id.ID equals jbs.ID select jbs).AsQueryable();

Filling datatable with LINQ to Entity results so I can iterate though them

I have been trying to fill up a datatable with the LINQ results so I can iterate though the DT and print out the needed data but no matter how I try it cant convert the anonomus type into a datatable.
The LINQ I am using is:
using (var db = new SiteNavigation())
{
dtNavData= (from n in db.Navigation
join st in db.SectionTranslations
on n.SectionID equals st.Section.SectionID
where n.Category == Category && st.CultureID == CultureID
orderby n.Position ascending
select new
{
LinkAddress = st.Section.Type + "/" + st.Section.RouteName,
st.Title
}).ToList();
}
Is there some way to get the results into a datatable or any other object so I can step though it row by row and process the data?
you don't have to create a DataTable, if all that you want is to iterate through the result of your linq query
var myResult = (from n in db.Navigation
join st in db.SectionTranslations
on n.SectionID equals st.Section.SectionID
where n.Category == Category && st.CultureID == CultureID
orderby n.Position ascending
select new
{
LinkAddress = st.Section.Type + "/" + st.Section.RouteName,
st.Title
}).ToList();
foreach(var item in myResult)
{
string linkAddrs = item.LinkAddress;
string title = item.Title;
}

Categories