LINQ to SQL Efficiency - c#

I am new to LINQ and I have a question regarding a "Hit the database once" type of transaction.
In the below code I am databinding the results of a query to a radio list. I want to run the query once, then work with the results before databinding. IE: If there are values, databind to the Radio list, otherwise show a textbox stating there are no values.
From my online searches I have only found that I can run the query once with a .count(), then run it again if the .count() is > 0.
I would prefer to hit the database once, then count the records, and proceed using the same resultset.
I was not sure of the terminology to use when searching, so please respond with the approprate terminology to use so that I can find the answer on my own!
using (RTOExceptionDataContext thisDataContext = new RTOExceptionDataContext())
{
rdoSelectTransition.DataSource = from tracking in thisDataContext.vw_RTOExceptionWorkflowTransitionMaps
where tracking.RTOExceptionId.Equals(Convert.ToInt32(Request.QueryString["RTOExceptionId"])) &&
tracking.RTOSecurityLevel.Equals((int)Master.thisUserSecurityLevel)
select new { tracking.RTOTransitionCd, tracking.TransitionDisp };
rdoSelectTransition.DataTextField = "TransitionDisp";
rdoSelectTransition.DataValueField = "RTOTransitionCd";
rdoSelectTransition.DataBind();
}

You don't need to do this at all. Just keep your binding code exactly as it is and use the <EmptyDataTemplate> within the markup of the GridView to indicate what should be shown in the event that you bind an empty collection to the GridView.
If you're binding data to a type of control that doesn't support a feature like this, then the easiest option is to simply eagerly materialize the query into a collection and then get the size of that in-memory collection.
var data = (from tracking in thisDataContext.vw_RTOExceptionWorkflowTransitionMaps
where tracking.RTOExceptionId.Equals(Convert.ToInt32(Request.QueryString["RTOExceptionId"])) &&
tracking.RTOSecurityLevel.Equals((int)Master.thisUserSecurityLevel)
select new { tracking.RTOTransitionCd, tracking.TransitionDisp })
.ToList();
if(data.Any())
//databind
else
//do something else

I did find an answer to my question! I am learning more about LINQ everyday, and I really love it! This allowed me to databind if there are results. Though the "else" is not shown below, it sets the visibility of the radio button to false.
int thisUserSecurityLevel = (int)Master.thisUserSecurityLevel;
int thisUserSelectedException = Convert.ToInt32(Request.QueryString["RTOExceptionId"]);
using (RTOExceptionDataContext thisDataContext = new RTOExceptionDataContext())
{
var query = from tracking in thisDataContext.vw_RTOExceptionWorkflowTransitionMaps
where tracking.RTOExceptionId.Equals(thisUserSelectedException) &&
tracking.RTOSecurityLevel.Equals(thisUserSecurityLevel)
select new { tracking.RTOTransitionCd, tracking.TransitionDisp };
if (query.Count() > 0)
{
rdoSelectTransition.DataSource = query;
rdoSelectTransition.DataTextField = "TransitionDisp";
rdoSelectTransition.DataValueField = "RTOTransitionCd";
rdoSelectTransition.DataBind();
}
}
}

Related

How do I load a DataGrid with data from a database using WPF and MVVM (revisited)?

I've been trying to follow the answer to #Jordan Palmer's question as I'm trying to do the same thing he was trying to do. I'm not seeing how to connect #Jordan Palmer's query (specifically the var variable) with the Records variable that would be in the LoadData() LINQ query shown in the ViewModel code panel. Would it be this:
Records = getTripInformation = from m in connection.tblTrips
where m.TripDate > DateTime.Today
select new { m.TripID, m.TripName, m.TripDate, m.ClosingDate, m.PricePerAdult, m.PricePerChild, m.Status };
I need some help on how to connect var to Records.
As #framps asked: "Do you have an example which you can provide for this as I'm struggling with the logic?"
The Records object is an observable collection. Every time you update it, it updates the datagrid. The LoadData method loads the records from the query into the Records object. For example
var getTripInformation = connection.tblTrips.Where(m => m.TripDate > DateTime.Today);
foreach(var r in getTripInformation)
Records.Add(r);

Searching for record in c# Winform (Entity Framework)

I have a c# winform with textboxes, connected via Entity Framework to a table, called Candidates (it has 700 records).
I'm using a BindingSource named candidatesBindingSource. Everything works as I want.
There is just one thing. I'm trying to implement searching candidates with surnames. So i have a Textbox, called textSurname and a Button with this code
for searching through my records:
var searchResults = (from a in _context.Candidates where (a.Surname.Contains(textSurname.Text)) select a.Id).ToList();
if (searchResults.Count > 0)
{
// Id of a record in searchResults is correct
var position = searchResults[0];
// This line moves focus to a wrong record
candidatesBindingSource.Position = position; //
}
If a record is found, I can get its Id. And here I have a problem. How can I reposition my candidatesBindingSource to the
record with the Id from my searchResults? For example, if I have an Id = 2638, the code above repositions my candidatesBindingSource
to the last record. I'm suspecting that this part candidatesBindingSource.Position actualy works as recordcount (700 in my table)
and is unable to go to the record nr. 2638 (not to the record with this Id). Am I right? So how can I implement a GOTO record with my found Id?
Do I really have to use a For loop with MoveNext command to compare my searched Id with all Id's?
Any hint would be very appreciated.
Ok, so this is how you initialize you binding source
candidatesBindingSource.DataSource = _context.Candidates.ToList();
Then you don't need to search the database, you can search the data source list using the List.FindIndex method like this:
var candidateList = (List<Candidate>)candidatesBindingSource.DataSource;
var searchText = textSurname.Text;
var firstMatchIndex = candidateList.FindIndex(c => c.Surname.Contains(searchText));
if (firstMatchIndex >= 0)
candidatesBindingSource.Position = firstMatchIndex;
I think you should set to candidatesBindingSource.Position index of item and not id.
That post will help you to get index of item correctly, witout read whole data again.
Get Row Index in a list by using entity framework
Also you can try get index from your binding source.
If you create a list out of your context it will have the same indexing as the databinding you set on your form. To set your form to look at the result of your search you can use the a match from the FindIndex() method of the list, and then set your .Position to that index.
using (Candidates _context = new Candidates())
{
var candidateList = _context.Candidate.ToList();
var firstCandidateMatchIndex = candidateList.FindIndex(c =>
c.Surname.Contains(textSurname.Text));
if (firstCandidateMatchIndex >= 0)
candidateBindingSource.Position = firstCandidateMatchIndex;
}

Silverlight C#: How to filter a combobox based on another combobox?

How to filter a combobox based on another combobox? ... again :)
I'm writing an web app to learn. I'm using Visual Studio 2012, Silverlight 5, C#, and SQl Server for the data source.
I have one table loading into a datagrid and comboboxes to filter the datagrid. Up to this point everything is working just right.
The comboboxes are "FilterState" and "FilterWaterWay". Note they are not in the datagrid.
I want to select a state and re-populate the FilterWaterWay with only those waterways in the state.
I've seen a lot of ways to do this but none of them seem to match my setup. I could be wrong and just not know it.
From a learning standpoint, I would like to know how to implement this in all 3 of the following query data examples but I'll settle for just one. The last one is my favorite.
Thanks for any and all help.
I would not mind using the following to load comboboxes, filtered or not, but I can't firgure out how to
Restirct the GetQuery to only one field
Make that field distinct
This loads all data from the GetQuery to the datagrid.
LoadOperation<MASTER_DOCKS> loadOp = this._DocksContext.Load(this._DocksContext.GetMASTER_DOCKSQuery());
DocksGrid.ItemsSource = loadOp.Entities;
This loads all data from the GetQuery to the datagrid after it's been filtered
EntityQuery<MASTER_DOCKS> query = _DocksContext.GetMASTER_DOCKSQuery();
query = query.Where(s => s.WTWY_NAME == WaterwaytoFilterBy && s.STATE == StateToFilterBy);
LoadOperation<MASTER_DOCKS> loadOp = this._DocksContext.Load(query);
DocksGrid.ItemsSource = loadOp.Entities;
This is how I am currently loading the comboboxes. This works fine for the load but I don't see how to filter.
The DomainService.cs does not know my other combobox (FilterState) that I want to use as the filter for this combobox (FilterWaterway).
If I could query the ObservableCollection in the xaml I might be able to get it to work but it seems kind of chunky.
Adapted from http://www.jonathanwax.com/2010/10/wcf-ria-services-datagrid-filters-no-domaindatasource-2/
XAML =
private ObservableCollection<string> waterWayFilterList;
public ObservableCollection<string> WaterWayFilterList
{
get { return waterWayFilterList; }
set { waterWayFilterList = value; }
}
private void DoPopulateFilter()
{
//Call Invoke Method to get a list of distinct WaterWays
InvokeOperation<IEnumerable<string>> invokeOp = _DocksContext.FillWaterWayList();
invokeOp.Completed += (s, e) =>
{
if (invokeOp.HasError)
{
MessageBox.Show("Failed to Load Category Filter");
}
else
{
//Populate Filter DataSource
WaterWayFilterList = new ObservableCollection<string>(invokeOp.Value);
//Add a Default "[Select]" value
WaterWayFilterList.Insert(0, "[Select WaterWay]");
FilterWaterWay.ItemsSource = WaterWayFilterList;
FilterWaterWay.SelectedItem = "[Select WaterWay]";
}
};
}
DomainService.cs =
[Invoke]
public List<string> FillWaterWayList()
{
return (from r in ObjectContext.MASTER_DOCKS
select r.WTWY_NAME).Distinct().ToList();
}
Here's the closest I've gotten so far and it seems straight forward.
It returns no errors but the displayed result reads System.Collections.Generic.List'1[System.Char]
The record count in the dropdown is correct which leads me to think it's on the right track.
Only what is displayed is wrong. A casting problem perhaps?
I would still have to get the result from the FilterState Combo box in where "TX" is.
var filter = from r in _DocksContext.MASTER_DOCKS
where r.STATE.Equals("TX")
select r.WTWY_NAME.Distinct().ToList();
MyComboBox.ItemsSource = filter;
Without parentheses, you're doing the .Distinct().ToList() on the string (which implements IEnumerable<char>, which is why those operations work), which results in a List<char> (which isn't what you're looking for). You need to add parentheses so you get the distinct waterways:
var filter = (from r in _DocksContext.MASTER_DOCKS
where r.STATE.Equals("TX")
select r.WTWY_NAME).Distinct().ToList();
Note that if two waterways might have the same name, but actually be distinct, you'll need to instead select distinct r, and then differentiate them in the dropdown somehow, e.g.
var filter = (from r in _DocksContext.MASTER_DOCKS
where r.STATE.Equals("TX")
select r).Distinct().ToList();
// generated classes are partial, so you can extend them in a separate file
public partial class MASTER_DOCKS
{
// the dropdown uses the ToString method to show the object
public override string ToString()
{
return string.Format("{0} ({1})", WTWY_NAME, ID);
}
}

Binding BindingList<string[]> to datagridview

Situation:
I am attempting to bind a BindingList<string[]> constructed from a LINQ to SQL query to a DataGridView.
Problem:
I either cannot make modification to the DataGridView after items are generated -or- I get a bunch of unwanted fields in my DataGridView (it depends on which iteration of my code I use) I have googled as hard as I can and tried implementing most of the solutions I have found online to no avail.
I know that string has no public property for its actual value. I am having a difficult time determining how to retrieve that (I believe is part of the problem).
C#
int item = (from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].Modules
where p.ModuleName.Equals(clbModules.SelectedItem)
select p.ModuleId)
.FirstOrDefault();
BindingList<string[]> Data = new BindingList<string[]>((
from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].QuestionAnswers
where p[2].Equals(item)
select new string[] { p[0].ToString(), p[3].ToString() })
.ToList());
dgvQuestions.DataSource = Data;
dgvQuestions.Refresh();
Unwanted Behavior:
This occurs after binding
Question:
Why is this happening?
How do I fix it?
Additional Information:
I am not sure what additional information may be need but I will supply what is requested.
Also if I switch to my other code iteration:
int item = (from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].Modules where p.ModuleName.Equals(clbModules.SelectedItem) select p.ModuleId).FirstOrDefault();
var Data = new BindingList<object>((from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].QuestionAnswers where p[2].Equals(item) select new {Question = p[0].ToString(), Answer = p[3].ToString() }).Cast<object>().ToList());
dgvQuestions.DataSource = Data;
dgvQuestions.Refresh();
dgvQuestions.Columns[1].ReadOnly = false;
I can see the data properly but I cannot edit the column I would like to.
You are binding to a list of string arrays, and you are getting the properties form the array. Most likely you want something like the following:
var Data = new BindingList<object>((
from p in CurrentConversion.Companies[lbCompanies.SelectedIndex].QuestionAnswers
where p[2].Equals(item)
select new {
Val1 = p[0].ToString(),
Val2 = p[3].ToString()
}).ToList());
The reason you're seeing those fields in the Grid is that you're binding each row to a string[]. So it is automatically displaying the properties of string[] as the columns. There is no built-in logic for the grid to parse an array and use the contents of the array as columns.
In order to get the DataGrid to display your data correctly, you should bind it to a custom type, and it will use the public properties of the type as columns.

IQueryable Select returns 0 records

Hello I am failry new to silverlight and C# and have a program that utilizes the RIA techinique of using data. I am having problems with selecting a single column from my datasource. I am trying to use the value of that column to populate a single series in my chart.
On my UI I have a Grid and a bar chart.
I am able to populate my Grid by using:
DomainContext ctx = new DomainContext();
ListingGrid.ItemsSource = ctx.v_IQ_Flashes;
ctx.Load(ctx.Get_Table1());
That populates my datagrid with all(*) fields from my table Table1
Now I want to populate a single series on my chart with just one column from that chart.
Using the following code yeilds a return value of 0 (which is incorrect). What am I doing wrong?
var slot = ctx.v_IQ_Flashes.Where(e => e.Year == t_year).Select(e => e.Win );
var sum_ret_slot = slot.Sum();
decimal sum_slot = sum_ret_slot.Value;
Note that all values, (Slot, sum_ret_slot, sum_slot) are all 0. I used the debugger to verify that these are indeed being called and that their values are all 0.
It seems to me that you aren't actually getting anything from your Where clause.
Does removing the where clause cause it to work, it so I would evaluate that and determine why that isn't matching any records.
I agree with msarchet - check the value of your t_year variable - are there any rows which actually match your Where predicate?
Do you get results if you change the code to:
var slot = ctx.v_IQ_Flashes.Select(e => e.Win );
var sum_ret_slot = slot.Sum();
decimal sum_slot = sum_ret_slot.Value;
Or do you get results if you change the code to:
var slot = ctx.v_IQ_Flashes.Where(e => e.Year == 2010).Select(e => e.Win );
var sum_ret_slot = slot.Sum();
decimal sum_slot = sum_ret_slot.Value;
Where do you add code of sum_slot getting?
If you do it consequentially with loading, zero results are right cause ctx.Load(ctx.Get_Table1()) is async operation and if next your step is filter, data is not loaded yet.
I think, first way to make this code right - add filter to callback
ctx.Load(ctx.Get_Table1(), ()=>{//get sum_slot }, null);
Second way - apply filter to query:
ctx.Load(ctx.Get_Table1().Where(e => e.Year == t_year)) - context will load filtered items.

Categories