LINQ Query find columns where string contains any letter - c#

I'm trying to find all customer codes where the customer has a status of "A" and whose code does not contain any letter using LINQ query.
var activeCustomers = Customers.Where(x => x.Status == "A" && x.Code.Any(n => !char.IsLetter(n))).Select(x => x.Code);
When I run this query in LinqPad I get the following error:

You'll need to do this as a two part query. First, you could get all the users who's status is "A":
var activeCustomers = Customers.Where(x => x.Status == "A").ToList();
After you've got those in-memory, you can create an additional filter for char.IsDigit:
var codes = activeCustomers.Where(x => x.Code.Any(n => !char.IsLetter(n)))
.Select(x => x.Code)
.ToArray();

As commenters have stated, IsLetter() cannot be translated to SQL. However, you could do the following, which will first retrieve all items with Status "A" from the database, then will apply your criteria after retrieval:
var activeCustomers = Customers.Where(x => x.Status == "A").AsEnumerable().Where(x => x.Code.Any(n => !char.IsLetter(n))).Select(x => x.Code);
You'll have to determine if it's acceptable (from a performance perspective) to retrieve all customers with "A" and then process.
The AsEnumerable() transitions your LINQ query to working not with IQueryable (which works with SQL) but with IEnumerable, which is used for plain LINQ to objects.

Since it is LINQ 2 SQL, there is no natural way to translate char.IsLetter to something SQL can understand. You can hydrate a query that retrieves your potential candidates and then apply an addition in-memory filter. This also solves the issue where LINQ 2 SQL has a preference for a string and you are dealing with chars
var activeCustomers = Customers.Where(x => x.Status == "A").ToList();
var filteredCustomers = activeCustomers.Where(x =>
x.Code.Any(n => !char.IsLetter(n))).Select(x => x.Code).ToList();
There are two performance hits here. First, you're retrieving all potential records, which isn't too desirable. Second, in your above code you were only interested in an enumerable collection of codes, which means our query is including far more data than we originally wanted.
You could tighten up the query by only returning back to columns necessary to apply your filtering:
var activeCustomers = Customers.Where(x => x.Status == "A")
Select(x => new Customer{ Status = x.Status, Code = x.Code }).ToList();
You still return more sets than you need, but your query includes fewer columns.

Related

QueryOver in NHibernate

I'm lost when it comes to to QueryOver in NHibernate, I'm trying to query over a database and retrive 4 values of importans, the rest are unnecessary and take up processing power.
I'm trying this:
var ext = _session.QueryOver<ExternServiceSettings>()
.Where(x => x.ExternService == ExternServiceEnum.Outlook).List();
which works fine but takes too long and returns everything in the database. then I tried:
var ext = _session.QueryOver<ExternServiceSettings>()
.Where(x => x.ExternService == ExternServiceEnum.Outlook)
.List<ExternServiceSettings>()
.Select(y => y.UserName);
However this only return the username and won't let me fetch more than one value...
All help is appreciated!
We should use .SelectList()
Check the example from doc:
var selection =
session.QueryOver<Cat>()
.SelectList(list => list
.Select(c => c.Name)
.SelectAvg(c => c.Age))
.List<object[]>();
see more here:
16.7. Projections

Combine two condition from two table with OR clause in orchard HQL query

In orchard cms i want to write a query containing two condition over two different ContentPartRecord combined with OR clause. one possible way to combine conditions is :
var query = _contentManager.HqlQuery()
.Where(a => a.ContentPartRecord<ProductPartRecord>(), a => a.Eq("Title", "myTitle"))
.Where(a => a.ContentPartRecord<TitlePartRecord>(), a => a.Eq("Price", 1000))
.List();
but this one combines two condition with And clause. i think something like following along with some changes (which would be the answer for this question) could be the case:
var query = _contentManager.HqlQuery()
.Join(a => a.ContentPartRecord<ProductPartRecord>())
.Join(a => a.ContentPartRecord<TitlePartRecord>())
.Where(a => a.ContentItem(),
a => a.Or(p => p.Eq("ProductPartRecord.Price",
"1000"), t => t.Eq("TitlePartRecord.Title", "myTitle")))
.List();
but i couldn't get it working.any body have any suggestion?
When you use where clause in HqlQuery you need to pass Alias (as first parameter). Alias means that you will be apply where clause to specific table (class that represent this table). And when you use OR clause that you definitely need to compare columns of the specific table in two parts of OR clause (left and right from the OR clause). And i think this is not possible to do you need a standard way.
But you can use:
Action<IAliasFactory> productPartRecordAlias = x => x.ContentPartRecord<ProductPartRecord>().Named("productPartRecord");
Action<IAliasFactory> titlePartRecordAlias = x => x.ContentPartRecord<TitlePartRecord>().Named("titlePartRecord");
var query = _contentManager.HqlQuery()
.Join(productPartRecordAlias)
.Join(titlePartRecordAlias)
.Where(a => a.ContentItem(), p => p.Gt("Id", "0 AND (productPartRecord.Price = 1000 OR titlePartRecord.Title = 'myTitle')"));

Linq select with filtering not working

I'm trying to select one field last record in filtered database (this is different than last inserted record). I tried with following code in controller but instead of field value, i'm getting "true" or "false", depending on if there's results after filtering or not.
List<Pozicije> poz = new List<Pozicije>();
poz = db.Pozicijes.Where(p => p.grupa == grupa)
.OrderBy(p => p.sifra_pozicije).ToList();
string pos = poz.Select(p => p.sifra_pozicije.Contains(s)).LastOrDefault().ToString();
can someone point me how to get value i need instead?
Try this instead. I've combined both parts of your query into one.
var pos =
Convert.ToString(db.Pozicijes.Where(p => p.grupa == grupa
&& p.sifra_pozicije.Contains(s))
.OrderByDescending(p => p.sifra_pozicije)
.Select(p => p.sifra_pozicije)
.FirstOrDefault());
If it doesn't work, you may need to tell us what types s and sifra_pozicije are.
LastOrDefault is not supported with LINQ to Entities/LINQ TO SQL. You need to do OrderByDescending and then get First record. Like:
string pos = db.Pozicijes.Where(p => p.grupa == grupa && p.sifra_pozicije.Contains(s)))
.OrderByDescending(p=> p.sifra_pozicije)
.Select(r=> r.sifra_pozicije)
.First();

Linq Contains in one query

I have a List and i want to write a query about List's ids Contains specific table id.
i Write this and running true but i want to write all in same query..
List<int> tempList=yetkiUygulamaList.Select(y => y.Id).ToList();
query = query.Where(x => tempList.Contains(x.Uygulama.Id));
Wrong Query
query = query.Where(x => yetkiUygulamaList.Select(y =>y.Id).ToList().Contains(x.Uygulama.Id));
this must works
query = query.Where(x => yetkiUygulamaList.Any(y=>y.Id == x.Uygulama.Id));
you can perform a join, it would be more simple and suitable in your case.
If I understand, query is a "collection" of a class (let's call it AObj) containing a property Uygulama and the class Uygulama contains a property Id and yetkiUygulamaList is a "collection" of Uygulama
//will return a IEnumerable<AObj>
IEnumerable<AObj> query = query.Join(yetkiUygulamaList, a => a.Uygulama.Id, u => u.Id, (a,u)=>a);
ToList() materilizes by executing the query, and after that there is no way for NHibernate to understand that the first query should be included as a subquery.
Just remove the useless ToList():
IQueryable<int> tempList = yetkiUygulamaList.Select(y => y.Id); // removed here
query = query.Where(x => tempList.Contains(x.Uygulama.Id));
The above code will generate a single SQL query. If you want to stick it all in one C# code line, just get rid of the intermediary variable:
query = query.Where(x => yetkiUygulamaList.Select(y => y.Id).Contains(x.Uygulama.Id));

How to query (using LINQ) FormattedValues in Dynamics CRM 2011

I am using LINQ to retrieve Account type entities from Microsoft Dynamics CRM Online. I am unable to filter the list for a particular formatted value. I have the correct value, but am receiving zero records.
I'm creating my connection like this:
var connection = new CrmConnection("CRMOnline");
connection.ProxyTypesEnabled = true;
CrmOrganizationServiceContext _context = new CrmOrganizationServiceContext(connection);
I've tried:
List<Account> items = _context.CreateQuery<Account>()
.Where( c => ((OptionSetValue)c["new_accreditationstatus"]).Equals(7))
.ToList();
and
List<Account> items = _context.CreateQuery<Account>()
.Where( c => c.GetFormattedAttributeValue("new_accreditationstatus") == "7"
.ToList();
and
List<Account> items = _context.CreateQuery<Account>()
.Where( c => c["new_accreditationstatus"] == "7"
.ToList();
The last on throws a System.Format exception.
Filters on normal properties, i.e. .Where(c => c.AccountNumber.StartsWith("2010")) work perfectly fine.
You can only get access to the _____Set entities when generating the early-bound CRM file (look into crmsvcutil.exe/Xrm.cs online) and creating an early-bound derivative of CrmOrganizationServiceContext (commonly called XrmServiceContext). You can see the available constructors in the early-bound file.
So if you know the (int) value of the OptionSetValue in advance (7, in this case), you can just use this value as one of the arguments in the Where clause, as you've stated elsewhere:
.Where( c => c.new_AccreditationStatus.Value == 7)
EDIT (try this):
var list = _context.AccountSet.Where(c =>
c.FormattedValues["new_accreditationstatus"] == "7").ToList();
Another great question, but unfortunately, I think this will represent another failure/"limitation" of the Linq provider, which doesn't mention anything about FormattedValues as one of the permitted uses of the Where clause, though it is permitted as an item in the Select clause.
The actual values for OptionSetValues are stored in the StringMap entity, and incidentally enough, you can access the StringMap entity via Linq. An example is as follows.
// This query gets one permissible value for this entity and field.
var actualValue = _context.CreateQuery("stringmap")
.Where(x => x.GetAttributeValue<string>("attributename") == "new_accreditationstatus")
.Where(x => x.GetAttributeValue<int>("value") == "7")
.Where(x => x.GetAttributeValue<int>("objecttypecode") == Account.EntityTypeCode)
.Select(x => x.GetAttributeValue<string>("value"))
.Single();
However, trying to build on this with a subquery and a version of your original query, as in the below, results in an exception, also below.
var actualValues = _context.CreateQuery("stringmap")
.Where(x => x.GetAttributeValue<string>("attributename") == "new_accreditationstatus")
.Where(x => x.GetAttributeValue<int>("objecttypecode") == Xrm.Account.EntityTypeCode);
// This (modified) query uses the StringMap values from the previous query in
// a subquery, linking to the int (attributevalue) value that
// new_accreditationstatus represents.
List<Account> items = _context.CreateQuery<Account>()
.Where(c => actualValues
.Where(x => x.GetAttributeValue<int>("attributevalue") == c.new_accreditationstatus.Value)
.Select(x => x.GetAttributeValue<string>("attributevalue"))
.Single() == "7")
.ToList();
...throws an exception.
Privilege Type Read not defined on entity 'StringMap'.
Which is of course frustrating, because somehow, Linq allows you to query the string map in the first query.
So you'll have to first query the StringMap entity for the AttributeValue that corresponds to "7", then use that value in a new query that references that value as follows:
var actualValue = _context.CreateQuery("stringmap")
.Where(x => x.GetAttributeValue<string>("attributename") == "new_accreditationstatus")
.Where(x => x.GetAttributeValue<int>("value") == "7")
.Where(x => x.GetAttributeValue<int>("objecttypecode") == Account.EntityTypeCode)
.Select(x => x.GetAttributeValue<string>("attributevalue"))
.Single();
List<Account> items = _context.CreateQuery<Account>()
.Where(c => c.new_accreditationstatus = new OptionSetValue(actualValue)
.ToList();
If I can ever find a way to do all of this in one query, I will definitely edit and repost.
Have you seen the crmsvcutil extension that will generate enumerations for optionsets?

Categories