Subsonic SimpleRepository NullReferenceException in Contains with cast - c#

I have a problem with this subsonic3.0.0.4 find statement:
rep = new SimpleRepository(" ... ");
rep.Find<MyObject>( x => x.Code.ToString("00000").Contains("023") );
The Code field is Long value and the sql query that I need is:
*SELECT * FROM ... WHERE convert(varchar, Code) LIKE '%023%'*
When I execute it, NullReferenceException. Then problem is the Cast to string for the LIKE filter. But i don't kwnon how to resolve it.
The stack trace:
at SubSonic.SqlGeneration.ANSISqlGenerator.GenerateConstraints()
at SubSonic.SqlGeneration.ANSISqlGenerator.BuildSelectStatement()
at SubSonic.Query.SqlQuery.BuildSqlStatement()
at SubSonic.Query.SqlQuery.GetCommand()
at SubSonic.Query.SqlQuery.ExecuteTypedListT
at SubSonic.Repository.SimpleRepository.Find[T](Expression`1 expression)
at agf.FormMain.BindGrid() in C:\dev\localhost\AGF\trunk\AGF\FormMain.cs:line 351
Thank you!!

This is a "bug" - SubSonic tries to convert your expression in the where clause to an SQL statement. SubSonic gives it's best to convert the x.Code statement to a string but is not aware - and cannot guarantee for multiple database types - that your toString("00000") will be executed successfully.
The exception could be a bit more clear.
Try to convert your value in the "Contains" statement to something like "00023" and omit the format expression in your ToString - that should be functional equivalent and will work.

Related

LINQ issue with Equals statement

I'm getting an error for the following:
var answerList = (from answer in db.QuestionAnswers
where answer.tLoginID.Equals(tId) && answer.pLoginID.Equals(pId)
&& answer.Submitted.Equals(submittedVal)
select answer).ToList();
The error is:
Unable to create a constant value of type 'System.Object'. Only
primitive types or enumeration types are supported in this context.
However, when I change it to:
var answerList = (from answer in db.QuestionAnswers
where answer.tLoginID.Equals(tId) && answer.pLoginID.Equals(pId)
select answer).ToList();
Then I do this:
answerList.Where(x => x.Submitted.Equals(submittedVal));
It works... What am I missing? To me these statements are doing the same thing. But I'm not sure why it is working like this.
UPDATE:
I figured out after looking at the link that #SergeyLitvinov provided about .Equals that the column I was checking Submitted was actually a Boolean instead of an Integer once I made the types the same my statements worked. Although I did change it from .Equals to ==.
The error is from the LINQ to Entities query provider which is attempting to transform your query expression into a SQL statement. Your second example enumerates your LINQ to Entities query prior to testing for Submitted.Equals(submittedVal), which mean you're using standard LINQ to Objects in local memory (i.e. it is not converted to SQL).

Greater than comparison for strings in EF

First off, I don't have any controll over the database so I can't change anything there.
The field in the database is a varchar(50) and contains (for the records I'm interested in) a number. I'd like to get all of them with a number over 50. In SQL I just type:
SELECT Field FROM MyTable WHERE Field > '50'
That works fine even though I can agree the datatype should be something else.
In EF I'm trying:
query = query.Where(t => t.MyTable.Field > string);
There error is: Operator '>' cannot be applied to operands of type 'string' and 'string'
use int.Parse(str) C# is not implicitly typed - ergo you have to convert it to an integer, double etc befoe using the '>' operator. If you are not sure if the string will be a number then you can use int.tryparse(str)
Originally, I suggested the below code, which I tried and worked but not using EF entity set:
query = query.Where(t => int.TryParse(t.Mytable.Field, out number) && int.Parse(t.MyTable.Field) > int.Parse(string));
And then, after getting some good comments, I tried it on EF set, and that line itself worked, but after that line executes, I tried to so anything on the results of the query above (e.g. Count()), I got the below exception:
LINQ to Entities does not recognize the method 'Boolean TryParse(System.String, Int32 ByRef)' method, and this method cannot be translated into a store expression.

Why does this Linq query return 0 for Count()?

This seems like an inconsistency, but I'm probably just missing something obvious. The base query is:
var events = db.tbl_special_events.Where(x => x.TimeStamp >= startDate);
The apparent inconsistency comes when I run the following code block:
int c1 = 0;
foreach (var e in events)
{
if (e.TimeStamp.DayOfWeek.ToString() == "Tuesday") c1++;
}
int c2 = events.Where(e => e.TimeStamp.DayOfWeek.ToString() == "Tuesday").Count();
After that runs, c1 is 1832, but c2 is 0. What am I missing?
I recreated this test and found that it may be directly related to the DateTime function.
The query that is generated:
exec sp_executesql N'SELECT [t0].[User_ID], [t0].[Email], [t0].[Password], [t0].[BrandID], [t0].[CustomerID], [t0].[Created], [t0].[EndDate], [t0].[AccountStatusID], [t0].[Verified], [t0].[ResetPasswordFailCount], [t0].[ResetPasswordLocked]
FROM [dbo].[User] AS [t0]
WHERE ((CONVERT(NVarChar,CONVERT(Int,(DATEPART(dw, [t0].[Created]) + (##DATEFIRST) + 6) % 7))) = #p0) AND ([t0].[BrandID] = #p1)',N'#p0 nvarchar(4000),#p1 int',#p0=N'Tuesday',#p1=3
Notice where #p0=N'Tuesday'
Keeping in mind that IQueryable and IEnumerable differ in that where IEnumerable represents an actual .net object, IQueryable converts your expression into an actual SQL statement used to query the database. So any values that you provide in that expression are actually sent to the database.
It is returning 0 results because there is no match. Reason being, the date conversion in SQL returns a 2 instead of 'Tuesday'. You can test this if you replace Tuesday with 2 in your LINQ WHERE clause, it'll actually work. This will work after enumerating it since the results will have been successfully mapped into a usable .net object where the DateTime.DayOfWeek conversion to "Tuesday" will work properly.
Your count is acting on an IQueryable<Event> while e is an enumerated instance. Therefore, some operations might not work as they cannot be translated into SQL [Edit: or will be translated in nonsensical SQL].
To ensure your Where clause works add an AsEnumerable() before it. This converts the IQueryable<Event> into an IEnumerable<Event> and tells the linq provider that it should stop generating SQL at this point.
So, this statement should provide the correct result:
int c2 = events.AsEnumerable()
.Where(e => e.TimeStamp.DayOfWeek.ToString() == "Tuesday")
.Count();
The actual code that cannot be converted causes the problem in SQL is e.TimeStamp.DayOfWeek.ToString().
Alternatively you can use the System.Data.Objects.SqlClient.SqlFunctions (doc here) class to hint the linq provider what it should be doing in SQL.
Edit
As #Servy pointed out this is a Linq to SQL question. However, the problem is quite common so I leave the answer and do not delete it.
On looking at the OP again, there could be another variable to the whole game ... lazy loading.
In the foreach loop the TimeStamp is lazy loaded. In the count query the provider tries to construct an SQL query, during this construction it might not be able to work with ToString (which is known to be problematic) and evaluate e.TimeStamp.DayOfWeek.ToString() to something different than "Tuesday".
The AsEnumerable() forces the provider to stop generating SQL, so that e.TimeStamp is lazy loaded again.
The only way kowing exactly what is going on, is to use tracing tool on the DB (e.g. SQL Server Profiler) to actually see the query (or queries) executed on the server.
Edit 2
Building on #Sinaesthetic's answer the reason why 0 is returned is that the Query tries to compare "4" to "Tuesday" which returns false and therefore the correct result is false.
Can be tested by executing
select ((CONVERT(NVarChar,CONVERT(Int,(DATEPART(dw, getdate()) + (##DATEFIRST) + 6) % 7))))
against the DB.
However, this also shows that it is up to the provider to decide what SQL it generates. Also it is up to the provider to decide what statements it supports and which statements it doesn't.
It also shows that using AsEnumerable to stop the SQL generation process can have an infulence on the semantic evaluation of a query.

Convert a Method Syntax to its corresponding version in Linq Syntax

I'm pretty new at EF and Linq.
Please help me to convert this Method Syntax query to a Linq one.
Method Syntax to retrieve a single scalar variable from my DataBase using EF.
string myCategoryTitle = context.CmsCategories.SingleOrDefault(x => x.CategoryId == rowView.CategoryId).Title;
Title rappresent a propriety/field in my model.
Any idea how to do it using a Linq Syntax?
Thanks for your help!
I assume you mean using a query expression... in which case, you can't. There's no query expression syntax for SingleOrDefault.
You could use this though:
string myCategoryTitle = (from x in context.CmsCategories
where x.CategoryId == rowView.CategoryId
select x.Title).SingleOrDefault();
Note that this isn't quite the same as the current code, which will throw a NullReferenceException if SingleOrDefault(...) returns null...

Custom Method in LINQ to SQL query

Is it possible to use custom method In query for example:
var result = from u in context.MyTable where MyMethod(u) == 10 select u;
As Pranay explains, you cannot have a custom (C#) method as part of the LINQ to SQL query, because LINQ to SQL wouldn't be able to look at the expression tree of the method and so it cannot translate it to SQL.
One option that you have is to write your function in SQL and store it as a SQL function on the SQL Server (possibly, you could also use SQL CLR, but I have not tried that). Then you can add the function to your DataContext type and LINQ to SQL will translate it to calls to the function on SQL server. Something like:
var result = from u in context.MyTable
where context.MyMethod(u) == 10 select u;
The problem, of course, is that you'll need to write the function in SQL (I think SQL CLR could also work - not sure about the performance and other possible complications though)
I also wrote an article (some time ago) that shows how to do this when you write the "method" as an expression tree way (as a value of type Expression<Func<...>>), which is possible, because in this case, the code is compiled as an expression tree. However, there is some postprocessing that has to be done and you can still write just a single expression that can be easily inlined in the LINQ query.
Check this full article : What is and what isn't possible with linq
Following is not possible
// function used in filter
static bool MyFunc(Nwind.Product p)
{
return p.ProductName.StartsWith("B");
}
// query that uses MyFunc
var q =
from p in db.Products
where MyPriceFunc(p.UnitPrice) > 30m
select p
It compiles with no errors, but when you execute it LINQ to SQL throws an exception saying: "Static method System.Boolean MyTest(LINQTest.Nwind.Product) has no supported translation to SQL."
The exception is actually thrown when you try to fetch results from q (for example using the foreach statement), because LINQ to SQL attempts to convert the expression trees to T-SQL only when the results are needed and the query must be executed.
To fix the example you can simply copy the code that checks whether product name starts with "B" to the where clause of the query and it would work fine.
Yes, but if you are using Linq-to-Sql - your method has to have special code to handle to SQL conversion.

Categories

Resources