LINQ display row numbers - sql-server-2005

I simply want to include a row number against the returned results of my query.
I found the following post that describes what I am trying to achieve but gives me an exception
http://vaultofthoughts.net/LINQRowNumberColumn.aspx
"An expression tree may not contain an assignment operator"
In MS SQL I would just use the ROWNUMBER() function, I'm simply looking for the equivalent in LINQ.

Use AsEnumerable() to evaluate the final part of your query on the client, and in that final part add a counter column:
int rowNo = 0;
var results = (from data in db.Data
// Add any processing to be performed server side
select data)
.AsEnumerable()
.Select(d => new { Data = d, Count = ++rowNo });

I'm not sure whether LINQ to SQL supports it (but it propably will), but there's an overload to the Queryable.Select method that accepts an lambda with an indexer. You can write your query as follows:
db.Authors.Select((author, index) => new
{
Lp = index, Name = author.Name
});
UPDATE:
I ran a few tests, but unfortunately LINQ to SQL does not support this overload (both 3.5sp1 and 4.0). It throws a NotSupportedException with the message:
Unsupported overload used for query
operator 'Select'.

LINQ to SQL allows you to map a SQL function. While I've not tested this, I think this construct will work:
public partial class YourDataContext : DatContext
{
[Function(Name = "ROWNUMBER")]
public int RowNumber()
{
throw InvalidOperationException("Not called directly.");
}
}
And write a query as follows:
from author in db.Authors
select new { Lp = db.RowNumber(), Name = author.Name };

Related

.NET Core - EF - trying to match/replace strings with digits, causes System.InvalidOperationException

I have to match records in SQL around a zip code with a min/max range
the challenge is that the data qualities are bad, some zipcodes are not numbers only
so I try to match "good zip codes" either by discarding bad ones or even keeping only digits
I dont know how to use Regex.Replace(..., #"[^\d]", "") instead of Regex.Match(..., #"\d") to fit in the query bellow
I get an error with the code bellow at runtime
I tried
Regex.IsMatch
SqlFunctions.IsNumeric
they all cause errors at runtime, here is the code :
var data = context.Leads.AsQueryable();
data = data.Include(p => p.Company).Include(p => p.Contact);
data = data.Where(p => Regex.IsMatch(p.Company.ZipCode, #"\d"));
data = data.Where(p => Convert.ToInt32(p.Company.ZipCode) >= range.Min);
data = data.Where(p => Convert.ToInt32(p.Company.ZipCode) <= range.Max);
here is the error :
System.InvalidOperationException: The LINQ expression 'DbSet<Lead>
.Join(
outer: DbSet<Company>,
inner: l => EF.Property<Nullable<int>>(l, "CompanyId"),
outerKeySelector: c => EF.Property<Nullable<int>>(c, "Id"),
innerKeySelector: (o, i) => new TransparentIdentifier<Lead, Company>(
Outer = o,
Inner = i
))
.Where(l => !(Regex.IsMatch(
input: l.Inner.ZipCode,
pattern: "\d")))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
I am not sure how to solve this. I really don't see how AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync() could help here
what do I do wrong ?
thanks for your help
Wnen you use querable list, Ef Core 5 is always trying to translate query to SQl, so you have to use code that SQL server could understand. If you want to use C# function you will have to download data to Server using ToList() or ToArray() at first and after this you can use any c# functions using downloaded data.
You can try something like this:
var data = context.Leads
.Include(p => p.Company)
.Include(p => p.Contact)
.Where(p =>
p.Company.Zipcode.All(char.IsDigit)
&& (Convert.ToInt32(p.Company.ZipCode) >= range.Min) //or >=1
&& ( Convert.ToInt32(p.Company.ZipCode) <= range.Max) ) // or <=99999
.ToArray();
I tried everything imaginable
all sorts of linq/ef trickeries, I even tried to define a DBFunction that was never found
once I had a running stored procedure written dirrectly in SQL, I ended up with a list, not with an IQueryable, so I was back to #1
finaly, I just created a new field in my table :
ZipCodeNum
which holds a filtered , converted version of the zipcode string

Nhibernate Linq & operator RegisterFunction Firebird

I am using NHibernate with Firebird and would like to create the bitwise and operator to the Firebird function bin_and(a, b)
Something like this:
var result = customers.Where(c => (c.StatusValue & 3) > 0);
The above query will result in something like that:
select * from customers where (StatusValue & 3) > 0
Which is not valid in Firebird, the result should be:
select * from customers where bin_and(StatusValue,3) > 0
Is there a possibility to overwrite this translated result ?
Update
By declaring a function this is possible:
[LinqExtensionMethod("BIN_AND")]
public static int BinAnd(int a, int b)
{
return a & b;
}
var result = customers.Where(c => BinAnd(c.StatusValue, 3) > 0);
This works, but I am searching for a more generic way wizh the '&' or '|' operator...
Update:
# Fédéric:
I wrote my own Dialect class like this:
public class MyFirebirdDialect: FirebirdDialect {
public MyFirebirdDialect()
{
// Bitwise operations
RegisterFunction("band", new BitwiseFunctionOperation("bin_and"));
RegisterFunction("bor", new BitwiseFunctionOperation("bin_or"));
RegisterFunction("bxor", new BitwiseFunctionOperation("bin_xor"));
RegisterFunction("bnot", new BitwiseFunctionOperation("bin_not"));
}
}
I had to import the BitwiseFunctionOperation.cs too
If I debug the code I see that this class is used as Dialect, and I see that there is a custom function for the key 'band' that has a value 'bin_and' but a Query like this
var result = customers.Where(c => (c.StatusValue & 3) > 0);
ends up in an sql like this :
select * from customers where (StatusValue & 3) > 0
I think the linq parser does not its part...
Are you using the appropriate dialect? FirebirdDialect correctly defines bitwise and in HQL (RegisterFunction("band", new BitwiseFunctionOperation("bin_and")); and linq-to-nhibernate translate & (ExpressionType.And) to the appropriate HQL call.
If you are using an old NHibernate version, maybe you need to upgrade.
Firebird bitwise operators have been added with NH-3630 in NHibernate 4.1.
You may try to back-port them in your project by using a custom dialect deriving from FirebirdDialect and registering those additional functions as illustrated in the link above, within your custom dialect constructor.
But that will not work, because it requires some other changes in NHibernate internals, not available before NHibernate 4.1. Maybe by patching a local copy of NHibernate 3.4 sources may you succeed in doing that.

Slick Plain Sql Generic Return Type

I am trying to write a configurable sql query executor using Slick. User provides a prepared statement with ? and at run time the exact query is formed by replacing ? with values.
Generally this is how one would run a plain sql query using slick.
val query = sql"#$queryString".as[(String,Int)]
In my case i would not know the result type so i want to get back a generic result type. Maybe a List of Tuples with each tuple representing a row of result SET.
Any ideas on how this would be done?
I found a solution from one of the scala git issues. Here it is
ResultMap extends GetResult[Map[String, Any]] {
def apply(pr: PositionedResult) = {
val resultSet = pr.rs
val metaData = resultSet.getMetaData();
(1 to pr.numColumns).map { i =>
metaData.getColumnName(i) -> resultSet.getObject(i)
}.toMap
}
and then we can simply do val query = sql"#$queryString".as(ResultMap)
Hope it helps!!

How to change sql generated by linq-to-entities?

I am querying a MS SQL database using Linq and Entity Framework Code First. The requirement is to be able to run a WHERE SomeColumn LIKE '%sometext'clause against the table.
This, on the surface, is a simple requirement that could be accomplished using a simple Linq query like this:
var results = new List<MyTable>();
using(var context = new MyContext())
{
results = context.MyTableQueryable
.Where(x => x.SomeColumn.EndsWith("sometext"))
.ToList();
}
// use results
However, this was not effective in practice. The problem seems to be that the column SomeColumn is not varchar, rather it's a char(31). This means that if a string is saved in the column that is less than 31 characters then there will be spaces added on the end of the string to ensure a length of 31 characters, and that fouls up the .EndsWith() query.
I used SQL Profiler to lookup the exact sql that was generated from the .EndsWith() method. Here is what I found:
--previous query code removed for brevity
WHERE [Extent1].[SomeColumn] LIKE N'%sometext'
So that is interesting. I'm not sure what the N means before '%sometext'. (I'll Google it later.) But I do know that if I take the same query and run it in SSMS without the N like this:
--previous query code removed for brevity
WHERE [Extent1].[SomeColumn] LIKE '%sometext'
Then the query works fine. Is there a way to get Linq and Entity Framework to drop that N from the query?
Please try this...
.Where(x => x.SomeColumn.Trim().EndsWith("sometext"))
Just spoke to my colleague who had a similar issue, see if the following works for you:
[Column(TypeName = "varchar")]
public string SomeColumn
{
get;
set;
}
Apparently setting the type on the column mapping will force the query to recognise it as a VARCHAR, where a string is normally interpreted as an NVARCHAR.

Method 'Boolean Contains(System.String)' has no supported translation to SQL

"Method 'Boolean Contains(System.String)' has no supported translation to SQL."
query is IsQueryable but this stopped working:
foreach (string s in collection1)
{
if (s.Length > 0)
{
query = query.Where(m => m.collection2.Contains(s));
}
}
UPDATE: it works when i make query "ienumerable" instead of iqueryable. What would be the way to get same result using linq instead of iterating through loop?
Try this:
query = query.Where(m => m.collection2.ToList().Contains(s));
^^^^^^^^
Take a look at this answer from stackoverflow.
It looks like the resulting query would need access to something that the database
has no way of reaching, because the info is in memory.
Since m.collection2 is in the database, don't use Contains. Use Any
m.collection2.Any(x => x == s)
It looks like the error you are seeing is coming from the collection collection 2. Have you tried wrappering the m.collection2 in another function which returns true or false? Is this LINQ syntax?