sqlexception index out of bounds with correct sql-statement - mysql

i've got an sql statement that works pretty well. but on implementing in my webapp working with play 2.1 i get this error:
javax.persistence.PersistenceException: Query threw SQLException:Column Index out of range, 0 < 1.
i found this question here: Error executing MySQL query via ebean using RawSql
but then i got other exceptions.
i'm trying to get tagged threads that contains a list of tags (same as stack overflow does).
here the sql statement
SELECT t.topic
FROM topic t
WHERE 3 = (SELECT COUNT( DISTINCT ta.id )
FROM topic_tag tt
INNER JOIN tag ta ON ta.id = tt.tag_id
WHERE ta.name IN ('children', 'spain','new')
AND tt.topic_id = t.id )
in play i do this:
RawSql rawSql = RawSqlBuilder.unparsed(sqlString).create();
result = find.setRawSql(rawSql).findList();
then, i got the out of bounds exception. after that i try to set column mappings:
RawSql rawSql = RawSqlBuilder.unparsed(sqlString)
.columnMapping("t.topic","topic")
.columnMapping("t.id","id")
.columnMapping("ta.name","tagList.name")
.columnMapping("ta.id","tagList.id")
.create();
now i get a null pointer exception. probably because ebean can't create a query from that.
here some code from my models:
#Entity
public class Topic extends Model{
#Id
public Long id;
#Required
public String topic;
#ManyToMany
public List<Tag> tagList;
}
#Entity
public class Tag extends Model {
#Id
public long id;
#Required
public String name;
}
after a lot of trying and frustrating i hope that somebody got a hint or a solution for this.

I just wasted few hours with similar problem, I actually managed to solve it by only mapping id field for certain kind of model and selecting lesser amount of fields, other values were automatically loaded after that - So basically, error occurred if I tried to select values like:
.. select e.id, e.name, e.description from exampleTable e .. and use mappings like:
RawSql rawSql = RawSqlBuilder.parse(sql)
// map the sql result columns to bean properties
.columnMapping("e.id", "exampleModel.id")
.columnMapping("e.name", "exampleModel.name")
.columnMapping("e.description", "exampleModel.description")
.create();
When I changed to select only e.id and map:
RawSql rawSql = RawSqlBuilder.parse(sql)
// map the sql result columns to bean properties
.columnMapping("e.id", "exampleModel.id")
.create();
It loaded also e.name and e.description to model values and errors disappeared.
(Of course my own query had several joins and were bit more complicated than this, but basics are the same.)
So to summarize: when this problem occurs, check that you are not loading anything twice (columnMapping), use System.out.println(""); or similar to check which values are already loaded for your model. Remember to also check annotations such as "#JoinColumn" which might load more data under same model - just based on given e.id value. If you dont select and set e.id as columnMapping value, then you might need to list all needed fields separately as .. e.name, e.description ..
Hopefully these findings helps someone out.

Related

SQLGrammar error when querying MySql view

When a run a GET request i get an exception o.h.engine.jdbc.spi.SqlExceptionHelper : Unknown column 'disburseme0_.reason_type' in 'field list' in stack trace even though i have configured the field correctly in the entity class. I have a Spring Boot SOAP interface that is querying a MySql database view. I have assigned one of the unique keys from the parent tables as the view Id in JPA.
Part of my entity class has:
#Entity
#Table(name="disbursement_payload")
public class Disbursement {
#Id
#Column(name="ID")
private long disbursementId;
#Column(name="ReasonType")
private String reasonType;
public long getDisbursementId() {
return disbursementId;
}
public void setDisbursementId(long disbursementId) {
this.disbursementId = disbursementId;
public String getReasonType() {
return reasonType;
}
public void setReasonType(String reasonType) {
this.reasonType = reasonType;
}
I have the view as:
CREATE VIEW disbursement_payload AS (
SELECT
iso_number AS Currency,
trans_desc AS ReasonType,
account_number AS ReceiverParty,
amount AS Amount
FROM m_payment_detail, m_loan_transaction
WHERE m_payment_detail.`id`= m_loan_transaction.`payment_detail_id` AND
m_payment_detail.`payment_type_id`=2
);
Is there something im missing , in the entity or view definition? I have read one of the comments here could not extract ResultSet in hibernate that i might have to explicitly define the parent schemas. Any assistance, greatly appreciated.
do the mapping for db column and class var name based on camelCase conversion basded on underscore _ separated name
you could try using
CREATE VIEW disbursement_payload AS (
SELECT iso_number AS currency
, trans_desc AS reason_type
, account_number AS receiver_rarty
, amount AS amount
FROM m_payment_detail
INNER JOIN m_loan_transaction
ON m_payment_detail.`id`= m_loan_transaction.`payment_detail_id`
AND m_payment_detail.`payment_type_id`=2
);
the view code is SQL code and hibernate see a view as a table, so the conversion of column name is base on the same rules
and a suggestion you should not use (older) implicit join based on where condition you should use (more recent) explici join sintax ..

using mysql "order by case" in hibernate criteria

I'm using Hibernate 4.3.1 final, Mysql 5.5 and I want to use an "order by case" order logic on some joined entities.
A pure sql representation of what I wish to achieve would look something like:
select adv.id, adv.published_date
from advert as adv
join account as act on act.id = adv.act_id
join account_status as aas on aas.id = act.current_aas_id
order by case aas.status
when 'pending' THEN 1
when 'approved' THEN 1
else 2
end, adv.published_date;
This orders the adverts of pending and approved accounts before those of deactive accounts.
I've managed to do all the select query using hibernate criteria, but I'm not sure how to specify the order by case statement using that api.
I found this post:
http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate-criteria-api/
but I need to reference joined entity classes in the order by case and I'm not sure how to do that.
Any help or suggestions much appreciated.
I think I found a solution.
In the end I created my own subclass of Order and overrode the public String toSqlString(Criteria,CriteriaQuery) method:
#Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) {
final String[] columns = criteriaQuery.getColumnsUsingProjection( criteria, getPropertyName() );
final StringBuilder fragment = new StringBuilder();
fragment.append(" case ").append(columns[0]);
fragment.append(" when 'pending' then 1 ");
fragment.append(" when 'approved' then 1 ");
fragment.append(" else 2 end");
return fragment.toString();
}
the important call (which I found in the original implementation of the order class) is the
criteriaQuery.getColumnsUsingProjection(criteria, getPropertyName());
Which gave me access to the alias for the column I wanted to order on using the case statement.
If anyone else is looking at this, if you are ordering on a property that is not on the root object, then make sure that you use aliases in your criteria joins and that you then reference those aliases correctly in the your custom Order propertyName when you instantiate it.
In addition to https://stackoverflow.com/a/24077763/258559
It is probably worth mention that now you're adding Order subclass like this
criteria.addOrder(new CustomOrder());
and not
criteria.addOrder(CustomOrder.desc(fieldName));
because desc/asc are the static methods which would still create an instance of Order instead of your CustomOrder

why this Linq to sql function return nulls?

I am new to linq to sql
I wrote this function:
public ICollection<ICustomer> GetAll()
{
DataClasses1DataContext context = new DataClasses1DataContext();
var customers = from customer in context.Customers select customer;
return customers.ToList().Cast<ICustomer>().ToList();
}
But it always return list of null values.
The database contain 3 records "filled with data" but this function return 3 nulls.
how to fix that?
It may not be able to cast the results properly, have you made your partial Customer object implement ICustomer? If not, that is the reason.
Also you don't have to bring it to a list twice, or even once for that matter since you aren't returning a list, it might be more appropriate to change your signature to List or IEnumerable depending on your usage.
You can test whether or not the cast is succeeding by doing a simple test.
DataClasses1DataContext context = new DataClasses1DataContext();
var customers = from customer in context.Customers select customer;
int numberOfCustomers = customers.Count();
var myCustomers = customers.Cast<ICustomer>(); //you could also do .OfType<ICustomer>();
int numberOfICustomers = myCustomers.Count();
If numberOfCustomers is 3 and numberOfICustomers is 0 then you know that was the issue.
Your problem is almost certainly at the .Cast() method (confirm this by stepping through your code & ensuring that customers is populated correctly).
Does the Customer object implement the ICustomer interface? It sounds like an obvious thing to check but that would be a likely problem.

N-Tiered LinqToSql Question

I am hoping you can help. I am developing a tiered website using Linq to Sql. I created a new class(or object) in DBML designer called memberState. This object is not an actual table in the database. I have this method in my middle layer:
public override IEnumerable(memberState) GetMembersByState(string #state)
{
using (BulletinWizardDataContext context = DataContext)
{
IEnumerable(memberState) mems = (from m in context.Members
join ma in context.MemberAddresses
on m.UserId equals ma.UserId
join s in context.States
on ma.StateId equals s.StateId
where s.StateName == #state
select new memberState
{
userId = m.UserID,
firstName = m.FirstName,
middleInitial = m.MiddleInitial,
lastName = m.LastName,
createDate = m.CreateDate,
modifyDate = m.ModifyDate
}).ToArray(memberState)();
return mems;
}
}
The tables in my joins (Members, States, and MemberAddresses are actual tables in my Database). I created the object memberStates so I could use it in the query above (notice the Select New memberState. When the data is updated on the web page how do I persist the changes back to the Member Table? My Member Table consists of the following columns: UserId, FirstName, MiddleInitial, LastName, CreateDate, ModifyDate. I am not sure how save the changes back to the database.
Thanks,
If I remember correctly, you can create a view from the different tables (Members, States, and MemberAddresses) and add that to the data context. Then any modifications to data in the view object can be saved, and linq to sql will handle the commit correctly as long as all the relationships are clearly setup/defined in both the database and in the data context.
If you have a Member table, the dbml will most likely contain a Member class. To update a member in the database, you will have to create a new Member object, and the Attach it to the BulletinWizardDataContext.Members collection. Something similar to the following code should the trick (I have not tested the code):
using (BulletinWizardDataContext context = DataContext)
{
Member m = new Member() { UserId = userId };
context.Members.Attach(m);
m.FirstName = firstName;
// Set other properties
context.SubmitChanges();
}
Attach must be called before setting the properties. Also, Linq2Sql has some issues with Attach in the case where the properties of your object are set to default values (i.e. 0 for numeric values, false for booleans, null for string etc.). In this case Attach will not generate the correct SQL.
var m = myContext.Members.Single(m=> m.UserID == myMemState.userID);
m.FirstName = myMemState.firstName;
m.MiddleInitial = myMemState.middleInitial;
...
That would be the quick way. It does an additional roundtrip to the db, but will work well. If that's an issue for you, then do Attach like Jakob suggested. For that you have to have to do some extra steps, like reviewing the configuration for optimistic updates and make sure you have the original fields when doing the attach.

Linq to SQL Stored Procedures with Multiple Results

We have followed the approach below to get the data from multiple results using LINQ To SQL
CREATE PROCEDURE dbo.GetPostByID
(
#PostID int
)
AS
SELECT *
FROM Posts AS p
WHERE p.PostID = #PostID
SELECT c.*
FROM Categories AS c
JOIN PostCategories AS pc
ON (pc.CategoryID = c.CategoryID)
WHERE pc.PostID = #PostID
The calling method in the class the inherits from DataContext should look like:
[Database(Name = "Blog")]
public class BlogContext : DataContext
{
...
[Function(Name = "dbo.GetPostByID")]
[ResultType(typeof(Post))]
[ResultType(typeof(Category))]
public IMultipleResults GetPostByID(int postID)
{
IExecuteResult result =
this.ExecuteMethodCall(this,
((MethodInfo)(MethodInfo.GetCurrentMethod())),
postID);
return (IMultipleResults)(result.ReturnValue);
}
}
Notice that the method is decorated not only with the Function attribute that maps to the stored procedure name, but also with the ReturnType attributes with the types of the result sets that the stored procedure returns. Additionally, the method returns an untyped interface of IMultipleResults:
public interface IMultipleResults : IFunctionResult, IDisposable
{
IEnumerable<TElement> GetResult<TElement>();
}
so the program can use this interface in order to retrieve the results:
BlogContext ctx = new BlogContext(...);
IMultipleResults results = ctx.GetPostByID(...);
IEnumerable<Post> posts = results.GetResult<Post>();
IEnumerable<Category> categories = results.GetResult<Category>();
In the above stored procedures we had two select queries
1. Select query without join
2. Select query with Join
But in the above second select query the data which is displayed is from one of the table i.e. from Categories table. But we have used join and want to display the data table with the results from both the tables i.e. from Categories as well as PostCategories.
Please if anybody can let me know how to achieve this using LINQ to SQL
What is the performance trade-off if we use the above approach vis-à-vis implement the above approach with simple SQL
Scott Guthrie (the guy who runs the .Net dev teams at MS) covered how to do this on his blog some months ago much better than I ever could, link here. On that page there is a section titled "Handling Multiple Result Shapes from SPROCs". That explains how to handle multiple results from stored procs of different shapes (or the same shape).
I highly recommend subscribing to his RSS feed. He is pretty much THE authoritative source on all things .Net.
Heya dude - does this work?
IEnumerable<Post> posts;
IEnumerable<Category> categories;
using (BlogContext ctx = new BlogContext(...))
{
ctx.DeferredLoadingEnabled = false; // THIS IS IMPORTANT.
IMultipleResults results = ctx.GetPostByID(...);
posts = results.GetResult<Post>().ToList();
categories = results.GetResult<Category>().ToList();
}
// Now we need to associate each category to the post.
// ASSUMPTION: Each post has only one category (1-1 mapping).
if (posts != null)
{
foreach(var post in posts)
{
int postId = post.PostId;
post.Category = categories
.Where(p => p.PostId == postId)
.SingleOrDefault();
}
}
Ok. lets break this down.
First up, a nice connection inside a using block (so it's disposed of nicely).
Next, we make sure DEFERRED LOADING is off. Otherwise, when u try and do the set (eg. post.Category == blah) it will see that it's null, lazy-load the data (eg. do a rountrip the database) set the data and THEN override the what was just dragged down from the db, with the result of there Where(..) method. phew! Summary: make sure deferred loading is off for the scope of the query.
Last, for each post, iterate and set the category from the second list.
does that help?
EDIT
Fixed it so that it doesn't throw an enumeration error by calling the ToList() methods.
Just curious, if a Post have have one or many Categories, is it possible to instead of using the for loop, to load the Post.PostCategories with the list of Categories (one to many), all in one shot, using a JOIN?
var rslt = from p in results.GetResult<Post>()
join c in results.GetResult<Category>() on p.PostId = c.PostID
...
p.Categories.Add(c)