I have a LINQ query like this:
from i in _db.Items.OfType<Medium>()
from m in i.Modules
from p in m.Pages
where i != null && i.Type == 1 && i.Published == true && p.PageId == 2
select p
I use the query like this because I have strongly typed view (ASP.NET MVC).
I need to have items sorted by the i.Sort property. orderby i.Sort and i.OrderBy(it => it.Sort) doesn't work. How can I fix this?
When sorting with Linq you usually give OrderBy a property, and eventually an IComparer, not a sorting function. For example:
class Person {
public int Age {get; set;}
}
public static void Main() {
var ps = new List<Person>();
ps.Add(new Person{Age = 1});
ps.Add(new Person{Age = 5});
ps.Add(new Person{Age = 3});
var sorted = ps.OrderBy(p => p.Age);
foreach(p in sorted) {
Console.WriteLine(p.Age);
}
}
Here Linq will know how to correctly sort integers.
Without giving more context (such as what exactly is i.Sort, what is its purpose, what do you want to do with it), it would be difficult to be more specific to your problem.
However, I'm pretty sure you are misunderstanding OrderBy: you should give it a lambda expression that identifies a property of the objects contained in your sequence, and then Linq will sort your sequence according to the usual order of the type of that property (or according to another order you define for that type, by using IComparer).
Let's say your Pages include page-numbers among their properties. Let's pretend this property is called "pagenumber". You would then add the following 'orderby' line between the 'where' and 'select' lines.
// (snip...)
where i != null && i.Type == 1 && i.Published == true && p.PageId == 2
orderby p.pagenumber
select p
Or maybe you don't have page numbers, but only page titles. You would do nearly the same thing:
where i != null && i.Type == 1 && i.Published == true && p.PageId == 2
orderby p.title
select p
Just from reading your code, I can't tell what criteria should be used for sorting. You need some kind of ordered element, an id number, a page number, or some text can be alphabetized.
from i in _db.Items.OfType<Medium>().OrderBy(x => x.Sort)
...
Related
I want to set a default value based on curUserid() in PurchCreateOrder. How can I put data in my field on form extension ?
Is there any better option of doing this ? Fields are bound to datasource and I have different fields with differentdatasources.
My code is giving me abnormal termination error with nullreferences. XPPCompiler
[ExtensionOf(tableStr(PurchTable))]
final class PurchCreateOrderGetDefAdress_Extension
{
void initvalue(PurchaseType _purchaseType)
{
next initvalue(_purchaseType);
PurchTable purchtable;
LogisticsPostalAddress logpostadress;
UserInfoSz usrsz;
str user = curUserId();
select firstonly logpostadress where logpostadress.city == 'lub';
// select firstonly InventSiteId, InventLocationId from purchtable join usrsz where purchtable.InventSiteId == usrsz.InventSiteId && usrsz.IsDefault == true;
select firstonly InventSiteId from usrsz where usrsz.UserId == user && usrsz.IsDefault == true;
purchtable.initValue();
purchtable.deliveryname = 'asasasasas' ;//logpostadress.Address;
purchtable.inventsiteid = usrsz.InventSiteId;
purchtable.inventlocationid = usrsz.InventSiteId;
info(strFmt("%1, %2, %3", logpostadress.Address, usrsz.InventSiteId));
}
}
The error is straight forward.
Error The augmented class 'PurchTable' provides a method by this name, but this method cannot be used as a chain of command method since the parameter profile does not match the original method.
Take a look at the highlighted parameter profile and compare to yours.
Edit: Take a look at these links for more info on Chain of Command (CoC):
https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/extensibility/method-wrapping-coc
https://channel9.msdn.com/Blogs/mfp/X-Chain-Of-Command (This video is excellent)
I completely understand that this is because LINQ query requires the whole expression to be translated to a server , and therefore I cant call an outside method in it. but as I have looked at other answers there is not relative solution to this. the only approach that I thought about is to loop through all the items in the model and than passing them to the query one by one but even though this approach would not help so I am seeking help in here for anyone to help me to figure out how to call a method or a way of calling a method appendstr that initializes a.PostedDate before checking its actual equivalent value in the giving LINQ Query.
[HttpGet]
public ActionResult SearchResult(int? page, string searchTitle = null, string searchLocation = null, string last24 = "")
{
ViewBag.searchTitle = searchTitle;
ViewBag.searchLocation = searchLocation;
ViewBag.page = page;
ViewBag.last24 = last24;
setUpApi(searchTitle, searchLocation);
var result = new List<AllJobModel>().AsQueryable();
if (!string.IsNullOrEmpty(ViewBag.searchTitle) || !string.IsNullOrEmpty(ViewBag.searchTitle) || !string.IsNullOrEmpty(ViewBag.last24))
{
setUpApi(searchTitle, searchLocation);
DateTime now = DateTime.Now;
result = db.AllJobModel.Where(a => a.JobTitle.Contains(searchTitle) && a.locationName.Contains(searchLocation) &&
appendstr(a.PostedDate).Equals(now.AddHours(-24).ToString("MM-dd-yyyy")));
}
else
{
result = from app in db.AllJobModel select app;
}
return View(result.ToList().ToPagedList(page ?? 1, 5));
}
The second method that gets called in the LINQ Query
public string appendstr(string str)
{
var x = str.Split(' ');
return 01 + "-" + x[1] + "-" + x[2];
}
I think you already understand that the .NET code you write in the Where clause is actually an expression that is parsed and converted to SQL. So if you have a funky string manipulation method, you can't use it directly.
The brute force option, as you seem to already understand, it to materialize the query first and then run the C# code over the results. You can do this with ToList() or AsEnumerable().
result = db.AllJobModel
.Where
(
a => a.JobTitle.Contains(searchTitle)
&& a.LocationName.Contains(searchLocation)
)
.AsEnumerable()
.Where
(
a => appendstr(a.PostedDate).Equals(now.AddHours(-24).ToString("MM-dd-yyyy")))
);
However in your specific case you can try a trick. You are attempting a date comparison, which SQL is perfectly capable of doing... you just need to convert that funky PostedDate to a SQL DateTime so that you can compare it directly. The gimmick for that is to use SqlFunctions.DateAdd to add null interval (e.g. 0 days). This implicitly converts the string to DateTime, where you can now query on the SQL side:
var targetDate = DateTime.Now.AddHours(-24);
result = db.AllJobModel
.Where
(
a => a.JobTitle.Contains(searchTitle)
&& a.LocationName.Contains(searchLocation)
&& SqlFunctions.DateAdd("DAY", 0, a.PostedDate) == targetDate
);
Credit goes to this post for the workaround.
I would like to retrieve the userInfoId from the database and pass it into var where the Login username is Kenny. However, the value returned to u was 0 instead of the desired value. I have tried selecting another username but the result was still the same.
var u = Database.UserInfo
.Where(userinfo => userinfo.LoginUserName == "BEN")
.Select(x=> x.UserInfoId)
.FirstOrDefault();
Put some breakpoints and see what you have inside u, Use the query below and you should be good to go. Make sure the table/column names are correct according to your db.
int userInfoId = (from x in context.UserInfo
where x.LoginUserName == "Kenny"
select x.UserInfoId).SingleOrDefault());
if (userInfoId > 0){
// user exists and do what you wish to next
}
else {
// user does not exist
}
How to validate whether the text in multiple textboxes are unique from each other.
It looks like that in asp.net but its not a valid syntax
bool hasNoDuplicate = (txtEmergencyName1.Text.Trim() <> txtEmergencyName2.Text.Trim() <> txtEmergencyName3.Text.Trim <> txtEmergencyName4.Text.Trim);
I am looking for an efficient appraoch, kind of lambda expression or inbuilt in asp.net
Since you're asking for lambda, here's a linq approach.
var allTxt = new[] { txtEmergencyName1, txtEmergencyName2, txtEmergencyName3, txtEmergencyName4 };
var allText = allTxt.Select((txt, i) => new { Text = txt.Text.Trim(), Pos = i + 1 }).ToList();
bool hasNoDuplicate = !allText.Any(t => allText.Skip(t.Pos).Any(t2 => t.Text == t2.Text));
Put all relevant TextBoxes in a collection like an array and use Enumerable.Any. By skipping all before the current textbox you avoid checking the TextBoxes twice.
If all relevant TextBoxes are in a container control like a Panel, you could also use Enumerable.OfType to find them:
IEnumerable<TextBox> allTxt = this.EmergencyPanel.Controls.OfType<TextBox>();
Side-note: it's premature optimization anyway to look for the most performant way to validate some controls. This is nothing what you are doing constantly and there are never millions of controls. Instead you should look for the shortest or most readable approach.
You can use and && or or || operator accordingly
bool isDuplicate=(txtEmergencyName1.Text.Trim() == txtEmergencyName2.Text.Trim()
&& txtEmergencyName2.Text.Trim() == txtEmergencyName3.Text.Trim);
it will set true or false in the isDuplicate variable.
Edit 1
bool isDuplicate=(txtEmergencyName1.Text.Trim() == txtEmergencyName2.Text.Trim()
&& txtEmergencyName2.Text.Trim() == txtEmergencyName3.Text.Trim
&& txtEmergencyName1.Text.Trim() == txtEmergencyName3.Text.Trim
);
You could also do something like
var test = new TextBox();
var AlltBox = new List<TextBox>() { new TextBox() };
for(int i=1; i == 5;i++)
AlltBox.Add((TextBox)this.FindName("txtEmergencyName"+i));
bool exist = AlltBox.Any(tb => ((tb.Text == test.Text)&& tb.Name != test.Name));
but i don't know about the performance
I have a basic search control which lists companies from a CRM depending on predefined search/filtering criteria supplied by dropdowns. The default selection is "ALL" for each DropDown, otherwise the user chooses a specific item(s). I'd like to be able to construct a Linq query dynamically based on the selections. Out of the 5 selectors they supply values that I can match against the Company table, but two of the selectors (if either or both are chosen) would require a join or joins, else no action should be taken again the base result set. I hope this makes sense.
I'm not sure how to do this effectively. Here is my code:
private void Search()
{
EnergyPubsCRMDataContext dc = new EnergyPubsCRMDataContext();
var results = (from c in dc.Companies
select c);
//only create the join if the selected index > 0
if (ddlIndustry.SelectedIndex > 0)
{
//A company can be in 1 or more industries, thus here I want to join
//with the CompanyIndustry table and have a WHERE clause to match on the ddlIndustry.SelectedValue
}
//only create the join if the selected index > 0
if (ddlServices.SelectedIndex > 0)
{
//A company can offer 1 or more services. Here I want to join to the CompanyService table
//on the CompanyID and have a WHERE clause to match the ddlServices.SelectedValue
}
//These work OK to shape the overal query further (they don't need joins)
if (ddlCountry.SelectedIndex > 0)
results = results.Where(c => c.CountryID == Convert.ToInt32(ddlCountry.SelectedValue));
if (ddlStateRegion.SelectedIndex > 0)
results = results.Where(c => c.StateRegionID == Convert.ToInt32(ddlStateRegion.SelectedValue));
if (ddlAccountManagers.SelectedIndex > 0)
{
Guid g = new Guid(ddlAccountManagers.SelectedValue);
results = results.Where(c => c.UserId == g);
}
results = results.OrderBy(c => c.CompanyName);
//Bind to Grid....
}
if (ddlIndustry.SelectedIndex > 0)
{
//A company can be in 1 or more industries, thus here I want to join
//with the CompanyIndustry table and have a WHERE clause to match on the ddlIndustry.SelectedValue
results = results.Where(c => c.CompanyIndustry.IndustryID == ddlIndustry.SelectedValue);
}
Assuming you have correct foreign keys in your database/DBML.
This will generate the join implicitly.
I had very similar issue and no foreign keys I could leverage.
My solution would translate to something like this:
results = results
.Join(dc.CompanyIndustry, c => c.CompanyID, ci => ci.CompanyID, (c, ci) => new { c, ci.IndustryID })
.Where (a => a.IndustryID == ddlIndustry.SelectedValue)
.Select(a => a.c);
Basically:
1) first we create a join, with a projection that gives us IndustryID (join)
2) we filter based on IndustryID (where)
3) we return original anonymous type, so that we can modify original query (select)