Generating dbcontext with sqlmetal creates my table value UDF columns as nullable - linq-to-sql

I've created a inline table UDF which have some various columns of different types.
ALTER FUNCTION [dbo].[fnTest]()
RETURNS TABLE
AS
RETURN
(
SELECT
[t0].[type],
[t0].[status],
[t0].[createdDate], -- datetime not null
[t1].[ACLID] -- bigint not null
FROM
[dbo].[ProcessInstanceWorkitem] AS [t0]
INNER JOIN [dbo].[Object] AS [t1] ON [t0].[objectID] = [t1].[objectID]
)
However, although some columns are set to not null sqlmetal.exe created them as nullable types:
public partial class FnTestResult
{
private string _Type;
private string _Status;
private System.Nullable<System.DateTime> _CreatedDate;
private System.Nullable<long> _ACLID;
...
Why doesn't it get the correct types which are not nullable?
I use sqlmetal (Microsoft (R) Database Mapping Generator 2008) version 4.0.30319.1 for .NET Framework version 4.

Related

Spring data repository with empty IN clause

I'm using Spring data JPA like this:
public interface SampleRepository extends CrudRepository<Sample, Integer>{
#Query("SELECT s FROM Sample s WHERE ((:ids) IS NULL OR s.id IN (:ids))")
List<Sample> queryIn(#Param("ids") List<Integer> ids);
}
But when ids is not empty, I got (1,2,3) is null which is incorrect in mysql.
If I write like this:
public interface SampleRepository extends CrudRepository<Sample, Integer>{
#Query("SELECT s FROM Sample s WHERE s.id IN (:ids)")
List<Sample> queryIn(#Param("ids") List<Integer> ids);
}
When ids is empty, I got s.id in (null)
If I must use native query to do this. Any suggestions?
I guess you want to use ISNULL function to see if :ids has a value or not
SELECT s FROM Sample s WHERE s.id IN (:ids)) or ISNULL(:ids) = 1

what it the JPQL jpa (#Query) for update column with binary operator mysql query?

SQL Query:
update de_meta set service_lines = service_lines | 5 where de_id = 20;
This works fine from SQL console.
JPA Query:
#Modifying
#Query("update DeMetaEntity set serviceLines = serviceLines | ?2 where deId = ?1")
void addDeServiceLineMap(Integer deId, int serviceLine);
This JPA query throws error because | (bitwise OR) is not valid in JPQL.
Is there any way to write equivalent JPQL for given SQL query?
I don't want to use criteria queries. As I use this at JAVA INTERFACE.
Create a native query as Alan suggested:
#Modifying
#Query("update de_meta set service_lines = service_lines | ?2 where de_id = ?1", nativeQuery=true)
void addDeServiceLineMap(Integer deId, int serviceLine);
The switch nativeQuery=true will execute the SQL query as it is.

Parameter index out of range with Multiple Join and Optional input parameter

I have an issue with the multiple Join using Spring JdbcTemplate if I need to make optional the input parameters.
This is the scenario.
The SQL table where i must perform the Join are:
CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(15),
password VARCHAR(20),
info VARCHAR(30),
active BOOLEAN,
locked BOOLEAN,
lockout_duration INT DEFAULT 0,
lockout_limit DATETIME,
login_attempts INT DEFAULT 0,
PRIMARY KEY(id)
);
CREATE TABLE profiles (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(15),
info VARCHAR(30),
PRIMARY KEY(id)
);
CREATE TABLE profiling(
user_id INT NOT NULL,
profile_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE,
PRIMARY KEY(user_id,profile_id)
);
Where profiling is the table to associate a user with his profile; the profile must be intended as the identification of what actions are permitted to users.
In one my precedent post, i ask how to make optional the sql parameters and I obtained a perfect response, that works and i have always used since then. So, if i need to make this, is put in the where:
WHERE (is null or variabile_name = ?)
And, using jdbctemplate, i write:
jdbcTemplate.query(SQL, new Object[]{variabile_name, variabile_name}, mapper_name);
where, of course, SQL is the String object where i make the Query.
So, i make this also in this case, but i got the error:
java.lang.IllegalStateException: Failed to execute CommandLineRunner
Caused by: java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).
I report the full method here:
/**
* This metod return the join between users and profiles
* made using the profiling table
*
* #param userID the user id code
* #param profilesID the profile id code
* #return the join list
*/
public List<Profiling> joinWithUsersandProfiles(Integer userID, Integer profileID)
{
//This is the mapper for Profiling
RowMapper<Profiling> profilingMapper = new RowMapper<Profiling>()
{
//This method must be implemented when we use a row mapper
public Profiling mapRow(ResultSet rs, int rowNum) throws SQLException
{
Profiling profiling = new Profiling();
profiling.setUser_id(rs.getInt("profiling.user_id"));
profiling.setProfile_id(rs.getInt("profiling.profile_id"));
//mapping users variabiles
profiling.setUsersId(rs.getInt("users.id"));
profiling.setUsersActive(rs.getBoolean("users.active"));
profiling.setUsersInfo(rs.getString("users.info"));
profiling.setUsersLocked(rs.getBoolean("users.locked"));
profiling.setUsersLockoutDuration(rs.getInt("users.lockout_duration"));
profiling.setUsersLockoutLimit(rs.getTime("users.lockout_limit"));
profiling.setUsersLoginAttempts(rs.getInt("users.login_attempts"));
profiling.setUsersName(rs.getString("users.name"));
profiling.setUsersPassword(rs.getString("users.password"));
//mapping profiles variabiles
profiling.setProfilesId(rs.getInt("profiles.id"));
profiling.setProfilesInfo(rs.getString("profiles.info"));
profiling.setProfilesName(rs.getString("profiles.name"));
return profiling;
}
};
/**
* This is the string that contain the query to obtain the data from profiling table.
* Please note that the notation "? is null or x = ?" means that the x variabile is optional;
* it can be asked as no making the query.
* If we give alla input equals null, it means that we must perform a SQl Select * From table.
*/
String SQL = "SELECT * FROM profiling JOIN users ON profiling.user_id = users.id JOIN profiles ON profiling.profile_id = profiles.id WHERE (is null or profiling.user_id = ?) AND (is null or profiling.profile_id = ?)";
/**
* The list containing the results is obtained using the method query on jdcbtemplate, giving in in input to it the query string, the array of object
* containing the input variabile of the method and the rowmapper implemented.
*/
List<Profiling> theProfilings = jdbcTemplate.query(SQL, new Object[]{userID, userID, profileID, profileID}, profilingMapper);
return theProfilings;
}
I know that the problem is made by the optional variabile. Why? if i try to remove the optional code and pass from:
(is null or variabile_name = ?)
to
variabile_name = ?
The code work perfectly.
So, what's my error here?
Edit: solved myself. I forgot the ? BEFORE the "is null" code. So, passing to:
(? is null or variabile_name = ?)
The code works.

JPA's Map<KEY, VALUE> query by JPQL failed

I am storing a Map in JPA , which stores a keyword translation in each language . such as one object stores Locale.ENGLISH -> "Father" , Locale.CHINESE -> "PaPa". And another object stores Locale.ENGLISH -> "Mother" , Locale.CHINESE -> "MaMa";
Here is my working design :
public class Relation {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#ElementCollection
#MapKeyColumn(name="locale")
#Column(name="value")
#CollectionTable(name = "RelationName", joinColumns = #JoinColumn(name = "relation_id"))
private Map<Locale, String> langMap = new HashMap<>();
// other fields skipped
}
It works well , I can store many keyword translations to DB. But when query with JPQL , it has some problems :
For example , I want to find which Relation has English key with value "Father" :
This is my code :
Relation r = em.createQuery("select r from Relation r join r.langMap m where ( KEY(m) = :locale and VALUE(m) = :value ) " , Relation.class)
.setParameter("locale" , locale)
.setParameter("value" , value)
.getSingleResult();
It generates this strange / not-working SQL :
Hibernate:
select
relation0_.id as id1_18_
from
Relation relation0_
inner join
RelationName langmap1_
on relation0_.id=langmap1_.relation_id
where
langmap1_.locale=?
and (
select
langmap1_.value
from
RelationName langmap1_
where
relation0_.id=langmap1_.relation_id
)=?
00:16:12.038 WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 1242, SQLState: 21000
00:16:12.038 ERROR o.h.e.jdbc.spi.SqlExceptionHelper - Subquery returns more than 1 row
I don't know why it generates that strange subquery.
I can solve this problem by Criteria :
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Relation> criteria = builder.createQuery(Relation.class);
Root<Relation> root = criteria.from(Relation.class);
criteria.select(root);
MapJoin<Relation , Locale , String> mapJoin = root.joinMap("langMap");
criteria.where(builder.and(
builder.equal(mapJoin.key(), locale) ,
builder.equal(mapJoin.value() , value))
);
return em.createQuery(criteria).getSingleResult();
It generates correct SQL ( where langmap1_.locale=? and langmap1_.value=? ) and works well.
But I feel Criteria is too complicated. And I wonder why the JPQL failed? How to correct the JPQL ?
Thanks.
Env :
JPA2 , Hibernate 4.2.3 , MySQL dialect
I had the same problem. It looks like accessing map by ref (without VALUE()) already gives you a map entry value, i.e. the next JPQL should be transformed to a valid SQL:
select r from Relation r join r.langMap m where ( KEY(m) = :locale and m = :value )
I had a similar problem using the JPQL VALUE() operator with Hibernate. It seems that Hibernate implements the VALUE() operator like the java.util.Map.values() method in Java. It generates a subquery that returns all values in the map, i.e. all rows of the mapping table that are related to the entity holding the Map attribute. As soon as you have more then one key/value pair in the map, a comparison expression, which expects scalar expressions as operands, will fail.
What you can do is to turn the comparison expression around and convert it to an IN expression.
Instead of:
select r from Relation r join r.langMap m
where ( KEY(m) = :locale and VALUE(m) = :value )
You can write:
select r from Relation r join r.langMap m
where ( KEY(m) = :locale and :value in (VALUE(m)) )
I hope this way your query will work.
The correct JPQL could be like this:
SELECT r FROM Relation r JOIN r.langMap map
WHERE map[:locale] = :value

Write this SQL query in LINQ to Entity format

I have this sql query need to convert to linq to entity
select kv.KeyID, kv.KeyVotID, v.VotID, v.FullName
from E_KeyVot kv
join E_Vot v
on kv.VotID = v.VotID
where kv.KeyID=2
order by v.FullName
This what I have tried but I'm sure it is not correct:
Public Function GetKeyVot() As IQueryable(Of Ems_KeyVot)
Try
Dim _objQuery As IQueryable(Of Ems_KeyVot, Ems_Vot) = _
From a In Context.Ems_KeyVot
Join b In Context.Ems_Vot On a.votid Equals b.votid
Where a.keyid = pub_KeyID
Order By b.FullName
Return _objQuery
Catch ex As Exception
End Try
End Function
Based on your query, the issue you have is that your return types don't agree with the query. The query returns an IQueryable(Of Ems_KeyVot, Ems_Vot), but your function is expecting an IQueryable(Of Ems_KeyVot).
In your query, you are projecting values from both tables. Since you can't return an anonymous type from your function, you need to create another class to return the results:
Public Class Votes
Public Property KeyID As Integer
Public Property KeyVotID As Integer
Public Property VotID As Integer
Public Property FullName As String
End Class
With that, you can modify your query as follows:
Dim _objQuery As IQueryable(Of Ems_KeyVot, Ems_Vot) = _
From a In Context.Ems_KeyVot
Join b In Context.Ems_Vot On a.votid Equals b.votid
Where a.keyid = pub_KeyID
Order By b.FullName
Select New Votes With { .KeyID = a.KeyID, .KeyVotID = a.KeyVotID, .VotID = b.VotID, .FullName = b.FullName }
Also change your function definition to
Public Function GetKeyVot() As IQueryable(Of Votes)
One other note, I see that you have a try catch block, but you aren't doing anything with the exception. If you can't handle an exception, remove the block and let it bubble up to something that can.