Updating ApplicationData record from the HTML client - c#

HTML Client Lightswitch:
In a ViewDetials screen i have a button where i would like to update my ApplicationData. However, the screens Dataworkspace does not contain the table i would like to update. My current button execute code looks like:
var filter = "SerialNumber eq " + screen.Hardware.SerialNumber; // Filter to find the Hardware Serial number in the active details window.
myapp.activeDataWorkspace.ApplicationData.Scans.filter(filter).execute().then(function (result) {
var scan = result.results[0];
scan.NoSticker = false; // Set the property to false
myapp.activeDataWorkspace.ApplicationData.saveChanges();
});
What I'm trying to do is update the NoSticker property on a record in the Scans table that matches the SerialNumber on my details screen. If i understand what I've been reading correctly, because the record is not in the screens Dataworkspace i have to query the Scans table in my ApplicationData. I can't recall ever having to do a query or a query with a filter in JS so I'm not sure If I'm even doing this correctly. When i click the button, nothing happens. Any guidance would be greatly appreciated.

At first glance, and assuming your SerialNumber is alphanumeric, the only issue with your approach appears to be the styling of your filter expression which should be as follows:
var filter = "SerialNumber eq " + msls._toODataString(screen.Hardware.SerialNumber, ":String");
This uses the standard LightSwitch library function to correctly markup your serial number value in the filter expression. In this case it basically wraps the value in single quotes as follows:
"SerialNumber eq 'ABC123'"
The _toODataString function also supports the following additional options for the second dataType parameters (covering the various LightSwitch data types):
":Binary", ":Binary?"
":Date", ":DateTime", ":Date?", ":DateTime?"
":DateTimeOffset", ":DateTimeOffset?"
":Decimal", ":Decimal?"
":Guid", ":Guid?"
":Int64", ":Int64?"
":Single", ":Single?"
":String", ":String?"
":TimeSpan", ":TimeSpan?"
":Byte", ":Byte?", ":Boolean", ":Boolean?", ":Double", ":Double?", ":Int16", ":Int16?", ":Int32", ":Int32?", ":SByte", ":SByte?"
Each of the groups above use the same markup approach e.g. ":Decimal" and ":Decimal?" are both suffixed by an M data type identifier. These markup options are a feature of the oData v3 protocol's filter operation used by LightSwitch.
As an alternative, you could always add a query against your Scans table which accepts the SerialNumber as a parameter and then call it as follows:
myapp.activeDataWorkspace.ApplicationData.ScanBySerialNumberQuery(screen.Hardware.SerialNumber).execute().then(function onComplete(result) {
if (result && result.results && result.results.length !== 0) {
var scan = result.results[0];
if (scan) {
scan.NoSticker = false; // Set the property to false
myapp.activeDataWorkspace.ApplicationData.saveChanges();
}
}
});
If you're still experiencing issues after trying the above approaches, the other aspect you could check is that your screen.Hardware.SerialNumber property is available at the point you're executing the search. If not, you may need to do the following:
screen.getHardware().then(function onComplete(hw) {
if (hw) {
myapp.activeDataWorkspace.ApplicationData.ScanBySerialNumber(hw.SerialNumber).execute().then(function onComplete(result) {
if (result && result.results && result.results.length !== 0) {
var scan = result.results[0];
if (scan) {
scan.NoSticker = false; // Set the property to false
myapp.activeDataWorkspace.ApplicationData.saveChanges();
}
}
});
}
});

Related

Sequence contains no match element but Element is there

I have a simple search box and button that is bound to a command, the command fires fine and passes the textbox parameter but when it hits the SearchStock method it runs through the list and doesn't match the parameter even though the element is there? Don't understand why its not matching, possibly my poor LINQ skills
Search Stock method
private void SearchStock(object _ticker)
{
var stock = Stocks.SingleOrDefault(x => x.Ticker == _ticker.ToString());
_selectedstock = (Stock)stock;
}
When I step into it it is showing the element ticker, I noticed that there were spaces after the Ticker name so I changed the column to NVARCHAR but it still didn't work
Ok so you find why it is not working all alone. "FB " is not equal to "FB".
You have 2 options :
Try to fix the used stored database string format.
use var stock = Stocks.SingleOrDefault(x => x.Ticker.Trim() == _ticker.ToString()); to ignore space in code

Lucene boosting not working

I'm indexing a document and setting the boost as follows:
document.SetBoost(5f);
because I want certain documents to appear before. For example, I want more recent news to show first.
When I do the search, like this:
var parser = new QueryParserEx(Version.LUCENE_29, "contents", analyzer);
parser.SetDefaultOperator(QueryParser.Operator.AND);
parser.SetMultiTermRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE);
Query query;
query = parser.Parse("text*");
The query gets parsed as a WildcardQuery and internally it's using this:
{Lucene.Net.Search.MultiTermQuery.AnonymousClassConstantScoreAutoRewrite}
Not sure why it's still using a Constant Score rewriter. Can someone explain?
I also believe I cannot use at search-time boosting as I don't need to boost certain terms, but certain documents (eg, most recent news appear first).
PS: This is not a duplicate of this question.
Nevermind. I was using a custom implementation of the QueryParser that had the method NewTermQuery overwritten.
Something like this:
protected override Query NewTermQuery(Term term)
{
var field = term.Field();
var text = term.Text() ?? "";
if (field == "contents" &&
text.Length >= 3 &&
text.IndexOfAny(new[] { '*', '?' }) < 0)
{
var wq = new WildcardQuery(new Term(field, text + "*"));
return wq;
}
return base.NewTermQuery(term);
}
And the WildcardQuery was not taking that configuration. All I had to do is call wq.SetMultiTermRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE); inside that if.

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;
}

Need to show appropriate message if no matching filterable records found

I have the following 2 simple requirements while dealing with Kendo Grid.
If there is no records present for the underlying datasource then display in the UI:
No records found. Please add New record using Add New button.
If records present but on user click on any column Filter, and No matching records found then display in the UI:
No matching records found for the given search criteria.
I have accomplished the 1st task using Grid's OnDataBound() method. I am just verifying the datasource length and displaying appropriate message in UI.
Please help me achieving the 2nd option. Because both of the case Grid's datasource length is 0 (zero).
You can query on the grid's dataSource's filter property. It will be undefined when filter is not defined or null when filters have been added but all have been removed.
So, basically your second option would be something like this or on the lines of this :
var grid = $("grid").data("kendoGrid");
if ((grid.dataSource.filter() != null) && (dataSource length is 0))
{
//Display No matching records found....
}
Finally, I got the clue:
function onDataBound(e) {
var filter = dataSource.filter();
var message;
if (this.dataSource._total === 0) {
if (filter && filter.filters.length) {
message = "No matching records found for the given search criteria.";
} else {
message = "No records found. Please add New record using Add New button.";
}
}

Linq to entities query optimizing

I have 3 tables in my DB which I'm working with:
Theme [Theme_ID]
ThemeWorkplace [Theme_ID, Workplace_ID, ThemeWorkplace_ID]
UserTheme [User_ID, Theme_ID, UserTheme_ID, UserTheme_AccessType]
I need to change UserTheme_AccessType for all UserTheme.Theme_ID in current workplace with ThemeWorkplace.Workplace_ID = 2 and current user with User_ID = 1. If theme is no row in UserTheme for such user and such theme - I need to create it.
I wrote such a code, but it works too long time:
var themeList = (from t in m_Entities.Theme
where (from tw in m_Entities.ThemeWorkplace
where tw.Workplace.Workplace_ID == 2
select tw.Theme.Theme_ID).Contains(t.Theme_ID)
select t)
.ToList();
foreach (Theme theme in themeList)
{
var oldUserTheme = GetByUserTheme(user/*user is given*/, theme);
if (oldUserTheme == null)
{
/* create new User Theme with params, that I need*/
this.Add(newUserTheme, true);
}
else
{
/* here - changing found row */
oldUserTheme.UserTheme_AccessType = 2;
}
}
I understand that this code accesses the database too many times. I want to find a way to get rid of:
var oldUserTheme = GetByUserTheme(user/*user is given*/, theme);
In every foreach iteration. Could somebody please help me?
Adding code of GetByUserTheme():
private UserTheme GetByUserTheme(User user, Theme theme)
{
return m_Entities.UserTheme.FirstOrDefault(ut => ut.User.User_ID == user.User_ID && ut.Theme.Theme_ID == theme.Theme_ID);
}
First: All changes for entities that you have done in code will be pushed to database in one batch command when you call context.SaveChanges. So you will have one request to Database for select and one request for update.
But in your batch command will be many sql queries for cause EF generate sql for updates entities one by one (not all in one).
If you want update really many records in database, you should use sql script (call stored procedure or execute sqlquery) against using EntityFramework.
I don't know if I'm completely understanding your question and structure. But based on what I see, could this be a reasonable slution?
First you select the workplaces that have ID equal to 2. From that result you select the theme-ID's. All your userthemes that have a themeID that occurs in the former result will then be selected into 'userThemes'. From there, you iterate over the results and if the userID is empty you create a new UserTheme, otherwise you update it.
Quick note: the code below is no real working code. It's just code I wrote to exemplify my explanation, kind of pseudo-code if you will.. :)
var userThemes = entities.Userthemes
.Where(ut => entities.Workplaces
.Where(w => w.WorkPlaceID == 2)
.Select(s => s.ThemeID)
.Contains(ut.ThemeID));
foreach (UserTheme ut in userThemes)
{
if (ut.UserID.ToString() == "")
{
//Create
}
else
ut.UserThemeAccessType = 2;
}

Categories