EF Code First - convert string to int in query - entity-framework

I need to convert String to Int32 value in my query. It must be done on sql server-side, not in memory.
I've seen answers how to do this in Model First approach, LINQ to Entities.
here and here
But I need it to be done with Code First.
I write query to DbSet<>.
Is there any way to do this? Please, help :)

New Answer:
The only way I can find information for is to use a custom query.
For instance:
from user in Users.SqlQuery("SELECT Id, CAST(Age AS INT) as Age, FirstName, LastName FROM Users")
select new
{
id = user.Id,
Age = user.Age
}
In my tests it seems every value for property on the entity you map to have to be included in the select even if you select to a custom object that do not include every property. In my example above I include FirstName and LastName even though they aren't used in the select.
Old answer:
About converting to string on sql-side:
You can use SqlFunctions.StringConvert if you cast your int to a double or decimal first
Problem with converting int to string in Linq to entities
from user in Users
select new
{
IdAsText = SqlClient.SqlFunctions.StringConvert((decimal)user.Id)
}
The cast to float or decimal is necessary because the STR-function on the sql-server requires a float: Why is there no int overload for SqlFunctions.StringConvert
Update:
In LINQPad the generated SQL-query from the above comes out to:
SELECT
[Extent1].[Id] AS [Id],
STR( CAST( [Extent1].[Id] AS decimal(19,0))) AS [C1]
FROM [dbo].[Users] AS [Extent1]

Related

Decoding Vapor raw query to MySQLModel

I'm trying to run a SQL Raw Query in a Vapor application, and decoded to a MySQLModel but apparently it returns an error.
final class ClassA: MySQLModel {
var id: Int?
var title: String
var description: String
}
But when I run a simple Select From raw query it returns a decoding error: "Value of type 'String' required for key 'title'." with it's weird because the sql run in the MySQL console does run correctly. The thing is when I decode the same query but instead of using a MySQLModel I use a Content like this:
final class ClassB: Content {
var id: Int?
var title: String
var description: String
}
And this is actually ends up decoding without errors.
Edit: The ClassA works perfectly with the regular ORM, it is only when I try to decode from Raw Query that it fails.
Edit: As ask by #Nick the sql does affect the response, when run:
SELECT * FROM ClassA
The return comes back with no error, but my sql includes a complex Subquery like this:
SELECT c.* FROM ClassA c WHERE c.id IN (SELECT id FROM ...);
Note: When run in MySQL Console the query returns no Error and as said the query can be decoded to a Content class exactly like ClassA Example: ClassB.
Edit: The code for running and decoding the raw query is simply:
return request.withNewConnection(to: .mysql) { (con) -> EventLoopFuture<[ClassA]> in
return con.raw(sql).all(decoding: ClassA.self).map { (classes) -> [ClassA] in
return classes
}
}
I resolve the problem by trying different permutation of the same Query as proposed that the problem was there by #Nick.
The problem lies here in the query (Not the Subquery as initially thought), the difference between this query:
SELECT * FROM ClassA;
And this query:
SELECT c.* FROM ClassA c WHERE c.id IN (SELECT id FROM ...);
besides the subquery is the naming of the table to "c" this notation for some reason is invalid for decoding the MySQLModel type in Vapor they will only work on Content types.
The solution is to remove the notation and use the entire name in the Query:
SELECT ClassA.* FROM ClassA WHERE ClassA.id IN (SELECT id FROM ...);

Is it possible to be able to accept many matrix parameters in my rest URL without having to declare them in my code?

I am developing a Restful WS which does the simple job of querying a DB and bringing back some data. The table that is querying has around 20 columns.
I want to be able to filter the my returned records by using the matrix parameters in the WHERE clause of my SQL statements.
For Example:
Lets say that we have the table People with the columns id, firstname, lastname
I want the URL http://localhost:808/myservice/people;firstname=nick
to bring me back all the people with firstname equals Nick (select * from people where firsname='Nick').
First of all, is this the correct practice to do that?
Second, in my tablet that I have 20 columns I must create a method in my Java code that will contain all the possible matrix parameters (see below) or there is a better way to do this?
public Response getPeople(#MatrixParam("id") String id,
#MatrixParam("firstname") String firstname,
#MatrixParam("lastname") String lastname,
#MatrixParam("antoherColumn") String antoherColumn,
#MatrixParam("antoherColumn") String antoherColumn,
#MatrixParam("antoherColumn") String antoherColumn,
#MatrixParam("antoherColumn") String antoherColumn,
#MatrixParam("antoherColumn") String antoherColumn,
#MatrixParam("antoherColumn") String antoherColumn,
#MatrixParam("antoherColumn") String antoherColumn,
#MatrixParam("antoherColumn") String antoherColumn,) {
}
Thanks in advance
First of all do not create your query by concatenating strings:
String q = "select * from where firstName = " + firstName //BAD!
You are asking for troubles like SQL injection attacks. If you use JDBC, use query parameters.
Since probably you want to use GET request, you can stick to your approach, use query parameters instead (#QueryParam). You might also consider the following approach:
http://localhost:808/myservice/people?filter=firstname:nick,lastName:smith
and method:
public Response getPeople(#QueryParam("filter") String filter) {
//if filter is not null, tokenize filter string by ',' then by ':'
//to get needed parameters
}
You should use #BeanParam in order to map the MatrixParam to an object.
This way you can keep the resource pretty simple, but still have the possibility to add more matrix parameters. Also, adding matrix params doesn't involve changing the resource at all. The #BeanParam works also with #PathParam and #QueryParam.
Example:
Consider this:
http://localhost:8081/myservice/people;firstname=nick,lastName=smith/?offset=3&limit=4
and then the resource:
#GET
public Response get(#BeanParam Filter filter, #BeanParam Paging paging) {
return Response.ok("some results").build();
}
and the Filter class looks like:
public class Filter {
public Filter(#MatrixParam("firstname") String firstname, #MatrixParam("lastname") String lastname) {}
}
and the Paging class:
public class Paging {
public Paging(#QueryParam("offset") int offset, #QueryParam("limit") int limit) { }
}
You can also use more filters, like Filter1, Filter2 etc in order to keep it more modular.
Using the matrix parameters the biggest advantage is caching. It makes even more sense if you have more than one level in you API, like ../animals;size=medium/mamals;fur=white/?limit=3&offset=4, because the query params would apply otherwise to all collections.

Why null and reference to null not the same thing

Why these two methods work differently:
public List<Foo> GetFoos()
{
int? parentId = null;
var l = _dataContext.Foos.Where(x => x.ParentElementId == parentId).ToList();
return l;
}
public List<Foo> GetFoos()
{
var l = _dataContext.Foos.Where(x => x.ParentElementId == null).ToList();
return l;
}
The first one returns nothing. Second returns what was expected. Data comes from EF. ParentElementId is nullable.
That is because you can't compare to null in SQL, it has the special IS NULL operator to check for null values.
The first query will be translated into a comparison, where the parameter is null:
WHERE ParentElementId = #param
This doesn't work, because comparing two null values doesn't yield true.
The second query will be translated into a null check, because the null value is a constant:
WHERE ParentElementId IS NULL
This works because EF is not fooled to translate it into a comparison.
I know, you got your answer but here is some additional insight:
This issue has been discussed on MSDN forums. Some people believe it's a bug, others say this is intentional behaviour due to performance reasons
It's always helps running EFProf or Sql Server Profiler (in case you are working with SQL Server. For example your two examples translate into two following statements respectively:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[ParentElementId] AS [ParentElementId]
FROM [dbo].[Foo] AS [Extent1]
WHERE [Extent1].[ParentElementId] = NULL
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[ParentElementId] AS [ParentElementId]
FROM [dbo].[Foo] AS [Extent1]
WHERE [Extent1].[ParentElementId] IS NULL
This technique (looking at generated SQL) is often very useful when dealing with problems in EF.
Captain Obvious: because parentId is not null, probably.
Response to edit: first one is not compilable. Type cannot be infered for null.
Response to another edit: Because EF query translates nullable types incorrectly probably

Entity Framework limit length of a returned nvarchar column

I want to limit the length of a column in an EF query, ala:
var query = from ce in entities.ContactEvents
.Include("Person")
.Include("Orders")
where ce.PersonID = personID
orderby ce.DateTimeContact descending
select new ContactEvent
{
ID = ce.ID,
DateTimeContact = ce.DateTimeContact,
Description = ce.Description.Substring(0, 500),
Orders = ce.Orders
};
The query fails because the EF can't project the complex type Orders.
The entity or complex type 'Model.ContactEvent' cannot be constructed in a LINQ to Entities query.
I've tried a few different ways to do the same thing such as use an explicit join in the LINQ expression but so far I always hit a snag populating the Orders collection in the select projection.
Any ideas on how I can construct my query? Ideally I don't even want to use a select projection but I'm assuming I need to in order to be able to limit the length of the description column returned from the database.
You cannot project to entity types. That is the limitation. If you want to return projection (calling select new) you must either return anonymous type or custom non entity type. If you want to return entity type you must always return whole column from linq-to-entities. You can try to trim the column after object is materialized by using:
var data = (from ce in entities.ContactEvents
.Include("Person")
.Include("Orders")
where ce.PersonID = personID
orderby ce.DateTimeContact descending
select ce)
.AsEnumerable()
.Select(e => new ContactEvent
{
ID = e.ID,
DateTimeContact = e.DateTimeContact,
Description = e.Description.Substring(0, 500),
Orders = e.Orders
});

EF and Chinese Simplified in where clause

I have a simply query where I want to pull data out based on a QueryString value. The query string gets passed in correctly to this EF statement:
_ctx.Products.Where(i => i.Category == CollectionName).ToList();
Looking at SQL Profiler the CollectionName above gets translated into ???
EX:
SELECT *
FROM [dbo].[Products] AS [Extent1]
WHERE [Extent1].[Category] = #p__linq__0',N'#p__linq__0 varchar(8000)',#p__linq__0='???'
How do I get Entity Framework to parse this correctly?