LINQ query where string does not contain a number - entity-framework

New to LINQ and I'm having trouble coming up with a simpler way to add a condition to exclude fields that contain numbers.
So far I've come up with:
db.MyDB.Where(x => !x.MyField.Contains('1') && !x.MyField.Contains('2') && !x.MyField.Contains('3') &&... etc.
There must be a better way to achieve this. I'm using entity framework.

Try something like this:
db.MyDB.Where(x => !x.MyField.Any(x => Char.IsDigit(x)))
You could also consider using a regex with \d.
There are a number of solutions, I suppose it comes down to what works best with whatever MyDB is in this scenario. You could make it more sql friendly by playing with SqlMethods
db.MyDB.Where(x => !SqlMethods.Like(x.MyField, "[0-9]"))

If this is linq to sql, use SqlMethods.Like
db.MyDB.Where(x => SqlMethods.Like(x.MyField, "%[0-9]%");
[edit] Well, it's not L2S, it's EF. I believe EF supports PatIndex
db.MyDB.Where(x => SqlFunctions.PatIndex("%[0-9]%", x.MyField) > 0);
(PATINDEX is 1-based, not 0 based)

Related

How do I use Entity Framework to find a record in Cosmos with case insensitive conditions

I know tis question has been asked several times on SO but I haven't found a solution that works.
It's clear that Cosmos is capable of case insensitive searches since June 2020 but I haven't managed to find a solution that works with EF.
For example...
await objDbContext.Tags.SingleOrDefaultAsync(t => t.Value.Equals("value", StringComparison.InvariantCultureIgnoreCase))
... throws the following exception:
System.InvalidOperationException: 'The LINQ expression 'DbSet()
.Where(t => t.Value.Equals(
value: "Value",
comparisonType: InvariantCultureIgnoreCase))' could not be translated. Additional information: Translation of the 'string.Equals' overload with a 'StringComparison' parameter is not supported. See https://go.microsoft.com/fwlink/?linkid=2129535 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
I've also tried .ToLower and string.Equals with similar results.
Is there a right way to do it? If not, is there an alternative? I'm happy to store the value in lowercase along side the actual value, to be used for searching only, but it must be updated automatically.
EF Core 5 has now implemented the transactions. Once you have updated you can change this line
await objDbContext.Tags.SingleOrDefaultAsync(t => t.Value.Equals("value", StringComparison.InvariantCultureIgnoreCase));
to
await objDbContext.Tags.SingleOrDefaultAsync(t => t.Value.ToLower() == "value");

TYPO3 queryBuilder: How to work with BINARY in where() clause?

I just have a short question.
There's no description in the following API overview of TYPO3 how to use a "BINARY" in where() clause: https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/ApiOverview/Database/QueryBuilder/Index.html#expr
What I want to achieve? this one:
WEHRE BINARY `buyer_code` = "f#F67d";
Actually I can only do the following:
->where(
$queryBuilder->expr()->eq('buyer_code', 'f#F67d')
);
But in this case I don't get a satisfying result for myself because I need case-sensitive here :-)
An another buyer_code exists "f#F67D" (the last char is uppercase) but I do need to look for the other one.
Thanks for helping.
Since TYPO3 is using Doctrine API here, you could try to do
->where('BINARY `buyer_code` = ' . $queryBuilder->createNamedParameter('f#F67d'))
Please keep in mind, that this query now only works for database backends, supporting the BINARY keyword!
Please have a look at Doctrine2 case-sensitive query The thread is a bit older, but seems to cover background and solution for your problem.

Performance issue with fluent query in EF vs SharpRepository

I was having some performance issues using SharpRepository, and after playing around the SQL Query Profiler I found the reason.
With EF I can do stuff like this:
var books = db.Books.Where(item => item.Year == '2016');
if (!string.IsNullorEmpty(search_author))
books = books.Where(item => item.Author.Contains(search_author);
return (books.ToList());
EF will not really do anything until books is used (last line) and then it will compile a query that will select only the small set of data matching year and author from the db.
But SharpRepository evaluates books at once, so this:
var books = book_repo.Books.FindAll(item => item.Year == '2016');
if (!string.IsNullorEmpty(search_author))
books = books.Where(item => item.Author.Contains(search_author);
return (books.ToList());
will compile a query like "select * from Books where Year == '2016'" at the first line, and get ALL those records from the database! Then at the second line it will make a search for the author within the C# code... That behaviour can be a major difference in performance when using large databases, and it explains why my queries timed out...
I tried using repo.GetAll().Where() instead of repo.FindAll().... but it worked the same way.
Am I misunderstanding something here, and is there a way around this issue?
You can use repo.AsQueryable() but by doing that you lose some of the functionality that SharpRepository can provide, like caching or and aspects/hooks you are using. It basically takes you out of the generic repo layer and lets you use the underlying LINQ provider. It has it's benefits for sure but in your case you can just build the Predicate conditionally and pass that in to the FindAll method.
You can do this by building an Expression predicate or using Specifications. Working with the Linq expressions does not always feel clean, but you can do it. Or you can use the Specification pattern built into SharpRepository.
ISpecification<Book> spec = new Specification<Book>(x => x.Year == 2016);
if (!string.IsNullorEmpty(search_author))
{
spec = spec.And(x => x.Author.Contains(search_author));
}
return repo.FindAll(spec);
For more info on Specifications you can look here: https://github.com/SharpRepository/SharpRepository/blob/develop/SharpRepository.Samples/HowToUseSpecifications.cs
Ivan Stoev provided this answer:
"The problem is that most of the repository methods return IEnumerable. Try repo.AsQueryable(). "

How do you update multiple columns using Slick Lifted Embedding?

How do you update multiple columns using Slick Lifted Embedding ? This document doesn't say much.
I expected it to be something like this
Query(AbilitiesTable).filter((ab: AbilitiesTable.type) => ab.id === ability_id).map((ab: AbilitiesTable.type) => (ab.verb, ab.subject)).update("edit", "doc")
With recent versions of Slick, this way of writing it works:
Users.filter(_.id === filterId)
.map(x => (x.name, x.age))
.update(("john", 99))
Be careful to remember the extra parentheses if you are updating more than one property otherwise you might get a compiler warning.
I figured it out. It should be like this
val map = Query(AbilitiesTable)
.filter(_.id === ability_id)
.map(ab => ab.verb ~ ab.context)
map.update(("", ""))
Typesafe, why your documentation is so bad ? I have to Google pretty much every silly thing or dig through unit-tests for hours. Please improve it. Thanks.

"LIKE" command in MongoDB(mongomapper)

how to use filter data as sql do "LIKE" in MongoDB, instead I using gem mongomapper on my rails apps? .thanks
If you're looking for partial matches on a string you can query with a regular expression. Here's the relevant part of the mongomapper docs:
http://api.mongodb.org/ruby/current/file.TUTORIAL.html#Querying_with_Regular_Expressions
Worth noting this from the Mongodb docs:
"For simple prefix queries (also called rooted regexps) like /^prefix/, the database will use an index when available and appropriate (much like most SQL databases that use indexes for a LIKE 'prefix%' expression). This only works if you don't have i (case-insensitivity) in the flags."
the closest thing to SQL LIKE would be /query/
ex:-
Person.where('name' => /John/).all => John F, John Doe, Johnny...etc
Edit: this is still case sensitive
try these it work for me :
#store_array=User.where(:$or => [{:first_name => /.#{#search_text}./i}, {:last_name => /.#{#search_text}./i}]).all();