ASP.NET my Linq code for nullable DateTime comparison is failing - asp.net

My app allows user to upload an XML file, which I pass as an XDocument into my method. All the values are attribute strings, and I am using Linq to XML and Linq to SQL.
The dateCutoff query is supposed to get the latest date from SQL table - InsDate is nullable.
The where clause in the inspections XML query is supposed to get inspection elements with the inspection_date attribute value later than the dateCutoff value. I am using DateTime.Parse and Date.CompareTo, but am coming up empty.
What am I missing? Any help is much appreciated.
public IEnumerable<XElement> getInspections(XDocument xDoc)
{
IEnumerable<XElement> inspections = null;
using (InspectionDataContext db = new InspectionDataContext())
{
// get the latest date already in Inspections table
DateTime? dateCutoff = (from d in db.Inspections
select d.InsDate).Max();
if (dateCutoff.HasValue)
{
dateCutoff = dateCutoff.Value.Date;
}
// get only the inspections later than the dateCutoff
inspections = from i in xDoc.Descendants("inspections")
where DateTime.Parse(i.Element("inspection").Attribute("inspection_date").Value).Date.CompareTo(dateCutoff) == 1
select i;
}
return inspections;
}

I'm gong to make a few assumptions here because it's not totally clear as written.
1. You want to return "inspection" elements (not the "inspections" container elements).
2. You want to return only elements whose dates are greater than the cutoff
3. If the cutoff is null, you want to return all inspections.
In that case, you'd do something like this:
var inspections = xDoc.Descendents("inspection");
if (!dateCutoff.HasValue)
return inspections;
return inspections.Where(i => (DateTime)i.Attribute("inspection_date") > dateCutoff.Value )

Here is what works:
DateTime? dateCutoff;
using (InspectionDataContext db = new InspectionDataContext())
{
// get the latest date already in Inspections table
DateTime? dateCutoffQ = (from d in db.Inspections
select d.InsDate).Max();
if (dateCutoffQ.HasValue)
{
dateCutoff = dateCutoffQ.Value.Date;
}
else
{
dateCutoff = DateTime.Now.AddYears(-20).Date;
}
string date1 = dateCutoff.ToString();
// get only the inspections later than the dateCutoff
inspectionList = from i in xDoc.Descendants("inspection")
where DateTime.Parse(i.Attribute("inspection_date").Value).Date > dateCutoff
select i;

Related

Number of records in grid AX 2012

I tried to count num of rows in grid in runtime with this code
FormRun caller;
FormDataSource fds;
QueryRun queryRun;
int64 rows;
fds = caller.dataSource();
query = fds.query();
queryRun = new QueryRun(query);
rows = SysQuery::countTotal(queryRun); //this returns -1587322268
rows = SysQuery::countLoops(queryRun); //this returs 54057
The last line of code is closest to what i need because there are 54057 lines but if i add filters it still returns 54057.
I want logic to get the number rows that grid has in the moment of calling the method.
Your query has more than one datasource.
The best way to explain your observation is to look at the implementation of countTotal and countLoops.
public client server static Integer countTotal(QueryRun _queryRun)
{
container c = SysQuery::countPrim(_queryRun.pack(false));
return conpeek(c,1);
}
public client server static Integer countLoops(QueryRun _queryRun)
{
container c = SysQuery::countPrim(_queryRun.pack(false));
return conpeek(c,2);
}
private server static container countPrim(container _queryPack)
{
...
if (countQuery.dataSourceCount() == 1)
qbds.addSelectionField(fieldnum(Common,RecId),SelectionField::Count);
countQueryRun = new QueryRun(countQuery);
while (countQueryRun.next())
{
common = countQueryRun.get(countQuery.dataSourceNo(1).table());
counter += common.RecId;
loops++;
}
return [counter,loops];
}
If your datasource contains one datasource it adds count(RecId).
countTotal returns the number of records.
countLoops returns 1.
Pretty fast, as fast as the SQL allows.
If your datasource contains more than one datasource it does not add count(RecId).
countTotal returns the sum of recIds (makes no sense).
countLoops returns the number of records.
Also countLoops is slow if there are many records as they are counted one by one.
If you have two datasources and want a fast count, you are on your own:
fds = caller.dataSource();
queryRun = new QueryRun(fds.queryRun().query());
queryRun.query().dataSourceNo(2).joinMode(JoinMode::ExistsJoin);
queryRun.query().dataSourceNo(1).clearFields();
queryRun.query().dataSourceNo(1).addSelectionField(fieldnum(Common,RecId),SelectionField::Count);
queryRun.next();
rows = queryRun.getNo(1).RecId;
The reason your count did not respect the filters was because you used datasource.query() rather than datasource.queryRun().query(). The former is the static query, the latter is the dynamic query with user filters included.
Update, found some old code with a more general approach:
static int tableCount(QueryRun _qr)
{
QueryRun qr;
Query q = new Query(_qr.query());
int dsN = _qr.query().dataSourceCount();
int ds;
for (ds = 2; ds <= dsN; ++ds)
{
if (q.dataSourceNo(ds).joinMode() == JoinMode::OuterJoin)
q.dataSourceNo(ds).enabled(false);
else if (q.dataSourceNo(ds).joinMode() == JoinMode::InnerJoin)
{
q.dataSourceNo(ds).joinMode(JoinMode::ExistsJoin);
q.dataSourceNo(ds).fields().clearFieldList();
}
}
q.dataSourceNo(1).fields().clearFieldList();
q.dataSourceNo(1).addSelectionField(fieldNum(Common,RecId), SelectionField::Count);
qr = new QueryRun(q);
qr.next();
return any2int(qr.getNo(1).RecId);
}

Sorting Gridview with Entity Framework Not Working as Intended

I have a gridview that i want to sort. I wrote the following method for it:
private void SortGridView(string sortExpression, string direction)
{
var constr = new AdminRequirementEF();
string sort = string.Concat("it.", sortExpression, " ", direction);
int pageSize = Convert.ToInt32(ddPageSize.SelectedItem.Text);
var results = constr.Projects;
int totalRecords = results.Count();
this.PopulatePager(totalRecords, pageIndex);
var sortedResults = constr.Projects.OrderBy(sort).Skip((pageIndex - 1) * pageSize).Take(pageNum).ToList();
grdMain.DataSource = sortedResults;
grdMain.DataBind();
}
The problem is sorting is applied on totalrecords not on per page filtered records. I want to use OrderBy(sort) after applying skip and take but it gives me an error stating skip can not be applied before orderby clause. Any help will be much appreciated.
You can get the constr.Projects collection sorted on its primary key
var results = constr.Projects.OrderBy(p => p.ProjectId)
and then apply the skip and take on the 'results' collection with sorting.
results = results.Skip((pageIndex - 1) * pageSize).Take(pageNum).OrderBy(sort).ToList();
This way you will get the records for particular page sorted as required.

Why is my query so slow?

I try to tune my query but I have no idea what I can change:
A screenshot of both tables: http://abload.de/image.php?img=1plkyg.jpg
The relation is: 1 UserPM (a Private Message) has 1 Sender (User, SenderID -> User.SenderID) and 1 Recipient (User, RecipientID -> User.UserID) and 1 User has X UserPMs as Recipient and X UserPMs as Sender.
The intial load takes around 200ms, it only takes the first 20 rows and display them. After this is displayed a JavaScript PageMethod gets the GetAllPMsAsReciepient method and loads the rest of the data
this GetAllPMsAsReciepient method takes around 4.5 to 5.0 seconds each time to run on around 250 rows
My code:
public static List<UserPM> GetAllPMsAsReciepient(Guid userID)
{
using (RPGDataContext dc = new RPGDataContext())
{
DateTime dt = DateTime.Now;
DataLoadOptions options = new DataLoadOptions();
//options.LoadWith<UserPM>(a => a.User);
options.LoadWith<UserPM>(a => a.User1);
dc.LoadOptions = options;
List<UserPM> pm = (
from a in dc.UserPMs
where a.RecieverID == userID
&& !a.IsDeletedRec
orderby a.Timestamp descending select a
).ToList();
TimeSpan ts = DateTime.Now - dt;
System.Diagnostics.Debug.WriteLine(ts.Seconds + "." + ts.Milliseconds);
return pm;
}
}
I have no idea how to tune this Query, I mean 250 PMs are nothing at all, on other inboxes on other websites I got around 5000 or something and it doesn't need a single second to load...
I try to set Indexes on Timestamp to reduce the Orderby time but nothing happend so far.
Any ideas here?
EDIT
I try to reproduce it on LinqPad:
Without the DataLoadOptions, in LinqPad the query needs 300ms, with DataLoadOptions around 1 Second.
So, that means:
I could save around 60% of the time, If I can avoid to load the User-table within this query, but how?
Why Linqpad needs only 1 second on the same connection, from the same computer, where my code is need 4.5-5.0 seconds?
Here is the execution plan: http://abload.de/image.php?img=54rjwq.jpg
Here is the SQL Linqpad gives me:
SELECT [t0].[PMID], [t0].[Text], [t0].[RecieverID], [t0].[SenderID], [t0].[Title], [t0].[Timestamp], [t0].[IsDeletedRec], [t0].[IsRead], [t0].[IsDeletedSender], [t0].[IsAnswered], [t1].[UserID], [t1].[Username], [t1].[Password], [t1].[Email], [t1].[RegisterDate], [t1].[LastLogin], [t1].[RegisterIP], [t1].[RefreshPing], [t1].[Admin], [t1].[IsDeleted], [t1].[DeletedFrom], [t1].[IsBanned], [t1].[BannedReason], [t1].[BannedFrom], [t1].[BannedAt], [t1].[NowPlay], [t1].[AcceptAGB], [t1].[AcceptRules], [t1].[MainProfile], [t1].[SetShowHTMLEditorInRPGPosts], [t1].[Age], [t1].[SetIsAgePublic], [t1].[City], [t1].[SetIsCityShown], [t1].[Verified], [t1].[Design], [t1].[SetRPGCountPublic], [t1].[SetLastLoginPublic], [t1].[SetRegisterDatePublic], [t1].[SetGBActive], [t1].[Gender], [t1].[IsGenderVisible], [t1].[OnlinelistHidden], [t1].[Birthday], [t1].[SetIsMenuHideable], [t1].[SetColorButtons], [t1].[SetIsAboutMePublic], [t1].[Name], [t1].[SetIsNamePublic], [t1].[ContactAnimexx], [t1].[ContactRPGLand], [t1].[ContactSkype], [t1].[ContactICQ], [t1].[ContactDeviantArt], [t1].[ContactFacebook], [t1].[ContactTwitter], [t1].[ContactTumblr], [t1].[IsContactAnimexxPublic], [t1].[IsContactRPGLandPublic], [t1].[IsContactSkypePublic], [t1].[IsContactICQPublic], [t1].[IsContactDeviantArtPublic], [t1].[IsContactFacebookPublic], [t1].[IsContactTwitterPublic], [t1].[IsContactTumblrPublic], [t1].[IsAdult], [t1].[IsShoutboxVisible], [t1].[Notification], [t1].[ShowTutorial], [t1].[MainProfilePreview], [t1].[SetSound], [t1].[EmailNotification], [t1].[UsernameOld], [t1].[UsernameChangeDate]
FROM [UserPM] AS [t0]
INNER JOIN [User] AS [t1] ON [t1].[UserID] = [t0].[RecieverID]
WHERE ([t0].[RecieverID] = #p0) AND (NOT ([t0].[IsDeletedRec] = 1))
ORDER BY [t0].[Timestamp] DESC
If you want to get rid of the LoadWith, you can select your field explicitly :
public static List<Tuple<UserPM, User> > GetAllPMsAsReciepient(Guid userID)
{
using (var dataContext = new RPGDataContext())
{
return (
from a in dataContext.UserPMs
where a.RecieverID == userID
&& !a.IsDeletedRec
orderby a.Timestamp descending
select Tuple.Create(a, a.User1)
).ToList();
}
}
I found a solution:
At first it seems that with the DataLoadOptions is something not okay, at second its not clever to load a table with 30 Coloumns when you only need 1.
To Solve this, I make a view which covers all nececeery fields and of course the join.
It reduces the time from 5.0 seconds to 230ms!

Can Sorting be performed on a Flex arrayCollection based on date/time values instead of normal text string / alpha?

I have a flex Array Collection created from a live XML data source and am trying to use my date/time string in the array to SORT the array prior to having the UI display the info / listing... currently the array is created and displays fine but the sorting by date / time is NOT working properly...
The routine works if I change the sort field (dataSortField.name) to 'name' (just alphanumeric text string based on filenames generated by my xml source), but if I use 'datemodified' as the sort field ( i.e. 7/24/2013 12:53:02 PM ) it doesn't sort it by date, just tries to sort alphabetically so the date order is not proper at all and for example it shows 1/10/2013 10:41:57 PM then instead of 2/1/2013 11:00:00 PM next it shows 10/10/2013 5:37:18 PM. So its using the date/time as a regular text string
// SORTING THE ARRAY BY DATE DESCENDING...
var dataSortField:SortField = new SortField();
dataSortField.name = "datemodified";
dataSortField.descending = false;
var arrayDataSort:Sort = new Sort();
arrayDataSort.fields = [dataSortField];
arr.sort = arrayDataSort;
arr.refresh();
Now if I CHANGE the dataSortField.name to "name" (which are alphanumeric filenames) it sorts a-z just fine... so How do I get it to sort by DATE where my array data looks like 7/24/2013 12:00:00 PM
Now the TIME part of the date isnt necessary for my sorting needs at all, so Im just looking to sort by date and beyond that the time doesnt matter for my needs but is hard coded in my xml data source.
I tried specifying
dataSortField.numeric = true;
but that didnt work either and while I can use it to specify string or numeric theres not a DATE option as I was expecting.
so my question, to clarify, is how do I make the SORT function acknowledge that I want to sort based on a series of date / time stamps in my array? Im using apache flex 4.9.1 / fb 4.6 premium).
I use this as a date compare function:
public static function genericSortCompareFunction_Date(obj1:Object, obj2:Object):int{
// * -1 if obj1 should appear before obj2 in ascending order.
// * 0 if obj1 = obj2.
// * 1 if obj1 should appear after obj2 in ascending order.
// if you have an XML Datasource; you'll have to do something here to get the
// date objects out of your XML and into value1 and value2
var value1:Date = obj1.dateField;
var value2:Date = obj2.dateField;
if(value1 == value2){
return 0;
}
if(value1 < value2){
return -1;
}
return 1;
}
To apply this to your code; you would do something like this:
var arrayDataSort:Sort = new Sort();
arrayDataSort.compareFunction = genericSortCompareFunction_Date;
arr.sort = arrayDataSort;
arr.refresh();

Error: FormatException was unhandled by user code in Linq how to solve?

Look please below this codes throw me : FormatException was unhandled by user code
Codes:
satis.KDV = Decimal.Parse((from o in genSatisctx.Urun where o.ID == UrunID select o.Kdv).ToString());
How can i rewrite linq query?
You are calling ToString on the query rather than a single result. Even though you may expect only one value to match your query, it will not return just a single value. You have to instruct it to do so using Single, First, Last or the variations of these that also return a default value (SingleOrDefault, FirstOrDefault, LastOrDefault).
In order to avoid an exception, you could change it to use Decimal.TryParse or you could change your code to use a default value if the LINQ query returns something that won't parse properly. I'd recommend the former or a combination.
Note that in the following example, I have added the call to SingleOrDefault. This ensures that only one value is parsed, even if no value is found, and that if there are multiple results, we get an exception (i.e. it enforces that we get exactly zero or one result to the query).
decimal parsedValue;
if (Decimal.TryParse(
genSatisctx
.Urun
.Where(o => o.ID == UrunID)
.Select(o=>o.Kdv)
.SingleOrDefault()
.ToString(), out parsedValue))
{
satis.KDV = parsedValue;
}
You're calling ToString() on an IQueryable<T> - what did you expect the string to be? It's very unlikely to be anything which can be parsed as a decimal number!
My guess is that you want to call First() or Single(), but we can't really tell without more information. What's the type of o.Kdv?
I suspect you either want:
satis.KDV = (from o in genSatisctx.Urun
where o.ID == UrunID
select o.Kdv).First();
or
string kdvString = (from o in genSatisctx.Urun
where o.ID == UrunID
select o.Kdv).First();
decimal kdv;
if (decimal.TryParse(kdvString, out kdv))
{
satis.KDV = kdv;
}
else
{
// What do you want to do if it's not valid?
}
When I use debug mode I see the data is update when over mouse, after end of this method ( it's show this message [input string was not in a correct format]
/* protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
try
{
TextBox name = (TextBox)GridView1.Rows[e.RowIndex].FindControl("txtEditName");
SqlDataSource2.UpdateParameters["Name"].DefaultValue = name.ToString();
TextBox age = (TextBox)GridView1.Rows[e.RowIndex].FindControl("txtEditAge");
SqlDataSource2.UpdateParameters["Age"].DefaultValue = age.ToString();
TextBox birthday = (TextBox)GridView1.Rows[e.RowIndex].FindControl("txtEditBirthday");
SqlDataSource2.UpdateParameters["Birthday"].DefaultValue = birthday.ToString();
DropDownList country = (DropDownList)GridView1.Rows[e.RowIndex].FindControl("DropEditCountry");
SqlDataSource2.UpdateParameters["CountryID"].DefaultValue = country.SelectedValue;
TextBox mobile = (TextBox)GridView1.Rows[e.RowIndex].FindControl("txtEditMobile");
SqlDataSource2.UpdateParameters["Mobile_No"].DefaultValue = mobile.ToString();
SqlDataSource2.Update();
}
catch (Exception j)
{
j.Message.ToString();
}
}
/* }

Resources