I have the following files in Play Framework 2.2.3
Controller:
public class Comment extends Controller
{
public Result create(UUID id)
{
models.blog.Blog blog = models.blog.Blog.finder.byId(id);
Result result;
if(blog == null)
{
result = notFound(main.render("404", error404.render()));
}
else
{
Form<models.blog.Comment> commentForm = Form.form(models.blog.Comment.class);
commentForm = commentForm.bindFromRequest();
if(commentForm.hasErrors())
{
result = badRequest(Json.toJson(commentForm));
}
else
{
models.blog.Comment comment = commentForm.get();
comment.setId(UUID.randomUUID());
comment.setTimeCreated(new Date());
comment.setBlogId(blog.getId());
comment.save();
result = ok(Json.toJson(comment));
}
}
return result;
}
}
And two models
#Entity
#Table(name="blog")
public class Blog extends Model
{
private static final SimpleDateFormat MONTH_LITERAL = new SimpleDateFormat("MMMMM"),
DAY_NUMBER = new SimpleDateFormat("d"),
YEAR_NUMBER = new SimpleDateFormat("yyyy");
public static Finder<UUID, Blog> finder = new Finder<UUID, Blog>(UUID.class, Blog.class);
#Id
#Column(name="id",length=36, nullable=false)
public UUID id;
#OneToOne
#JoinColumn(name="author_id")
public User author;
#Column(name="title",length=255)
public String title;
#Column(name="summary",length=255)
public String summary;
#Column(name="url",length=255)
public String url;
#Column(name="content")
public String content;
#Column(name="time_updated")
public Date time_created;
#Column(name="time_created", nullable=false)
public Date time_updated;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name="blog_id")
public List<Comment> comments;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name="blog_tag_map",
joinColumns={ #JoinColumn(name="blog_id", referencedColumnName="id") },
inverseJoinColumns={ #JoinColumn(name="tag_id", referencedColumnName="id") }
)
public List<Tag> tags;
public List<Comment> getComments()
{
return this.comments;
}
}
#Entity
#Table(name="blog_comment")
public class Comment extends Model
{
private static final SimpleDateFormat MONTH_LITERAL = new SimpleDateFormat("MMMMM"),
DAY_NUMBER = new SimpleDateFormat("d"),
YEAR_NUMBER = new SimpleDateFormat("yyyy");
#Id
#Column(name="id",length=36, nullable=false)
public UUID id;
#Column(name="blog_id", length=36)
public UUID blog_id;
#ManyToOne
public Blog blog;
#Column(name="content", length=500)
public String content;
#Column(name="website", length=255)
public String website;
#Column(name="name", length=255)
public String name;
#Column(name="time_created", updatable=false)
public Date time_created;
}
I have excluded some setters and getters from these models for brevity, so it doesn't clog up this post.
When I attempt to make a POST request to the aforementioned controller, everything goes fine until I get to the "comment.save()" statement in the controller file, then I get the following error.
I'm unsure why this save isn't going through, and why there is a column conflict.
Help much appreciated
The issue lies in the fact that you have defined basically two foreign key columns for Blog in your Comment's entity:
#Column(name = "blog_id", length = 36)
public UUID blog_id;
#ManyToOne
public Blog blog;
The default column name for your 'blog' field is: blog_id
However, you've already named your 'blog_id' column that.
Interestingly, no error/warning is thrown when creating this table...
So when you call comment.save(), the following insert statement is generated:
insert into blog_comment (id, blog_id, content, website, name, time_created, blog_id) values (?,?,?,?,?,?,?)
Notice a reference to 'blog_id' column twice, which is invalid.
And this is because of the above double mapping.
To fix, just give your 'blog' property a different name to use for the foreign key column:
#Column(name = "blog_id", length = 36)
public UUID blog_id;
#ManyToOne
#JoinColumn(name = "blogId")
public Blog blog;
I'm not sure why you're mapping your entities like this (perhaps legacy schema?) but the 'blog_id' fields seem to be redundant (and confusing) as you already have an entity mapping in the form of your 'blog' property.
This question is pretty old, but for any future reference i have found this answer that solved my problem.
After numerous searchers around the web I found this answer here - thanks to jtal!
Just to summaries the problem:
Using Ebean i have made a #ManyToOne entity that is not implemented in the database in anyway,
even more the join field, in your case
blogId
is a valid field that has values of its own.
when trying to join the column on that field, it will always fail because it creates this sql query:
SELECT
*
FROM
blog_comment;
select
t0.id c0,
t0.blog_id c1,
t0.content c2,
t0.website c3,
t0.time_created c4,
t0.blog_id c5 <---- notice this duplicate
from
blog_comment t0
in order to solve this, i tell ebean not to use the second set of properties.
your new ebean element should look something like this:
#ManyToOne
#JoinColumn(name = "blogId", insertable = false, updatable = false)
public Blog blog;
hope this helps! =)
Related
I have a hibernate entity Car
#Entity
#Table(name = "car")
public class Car extends AbstractEntityBean implements java.io.Serializable {
private Integer carId;
private Integer name;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "carId", unique = true, nullable = false)
public Integer getCarId() {
return this.carId;
}
public void setCarId(Integer carId) {
this.carId = carId;
}
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Then I try to search a car by example:
crit.add(example);
In "example" I set carName adn search works great, as expected.
But when I set carId in "example", carId is being ignored in search criteria and query returns all cars.
I did some debuggin and I see in hibernate-core-3.6.10.Final-sources.jar!\org\hibernate\tuple\entity\EntityMetamodel.java there is a property
private final String[] propertyNames;
I can see "name" on propertyNames list, but not cardId.
When I add annotation #Id to name instead of carId, carId shows up on propertyNames list and I can search by example where carId is set.
Question: How can I search by example using carId when #Id annotation is set at carId?
Thanks
As I remember from QBE with Hibernate criteria, this is the way it is designed. So short question, you can't query by the id using QBE. And it also doesn't make sense. When querying by id, you can only get one result.
As a side note: Hibernate 3.6 is quite old. Probably way out-of-date!
Could you help me solve a small question?
It's about the project with Spring Data, JPA and Hibernate.
I have 2 entities and I need to join one to another. Yes, it sounds simple :)
First is Activity:
public class Activity {
...
#Column(name="STATUS_ID")
private String statusId;
...
}
Second is Vocab Value (Users can administer it as a simple list of values):
public class VocabValue {
...
// Type of vocab (in our case - 'ACT_STAT')
#Column(name="TYPE")
private String type;
// Name - code of Vocab value
#Column(name="NAME")
private String type;
// Value
#Column(name="VAL")
private String value;
...
}
In my case, I want to store in an Activity a name of Vocab Value and join it.
In the target state, my entity should look like:
public class Activity {
...
#Column(name="STATUS_ID")
private String statusId;
#... what?
private String status;
// Getter returns Vocab Value in accordance with the following join spec (pseudo-sql):
// select voc.value from VocabValue voc where voc.name = %statusId% and type = 'ACT_STAT'
public String getStatus() {
}
...
}
How should I configure my Activity entity to provide this?
Ok, Is it possible?
I'll be grateful for your advice!
Thank!
Update 13.01
I've tried this solution:
public class Activity {
...
#Column(name="STATUS_ID")
private String statusId;
#JoinColumn(name = "STATUS_ID", referencedColumnName = "NAME", insertable = false, updatable = false)
#Where(clause = "type = 'ACT_STAT'")
#ManyToOne(optional = true)
#NotFound(action = NotFoundAction.IGNORE)
private VocabValue status;
...
}
Moreover, I had to make VocabValue implementation of Serializable (VocabValue as Detached entity should be implemetation of Serializable interface in accordance with Hibernate spec).
public VocabValue implemets Serializable {...}
It works, but annotation #Where doesn't work: Join performed only with #JoinColumn specification, an additional criteria, defined in #Where clause doesn't apply.
Whether there are workarounds?
UPDATE 13.01 - 2
It was solved with following configuration:
#JoinFormula(value="SELECT v.ROW_ID FROM VOCAB v WHERE v.NAME=STATUS_ID AND v.TYPE='ACT_STAT'")
#ManyToOne
#NotFound(action = NotFoundAction.IGNORE)
private VocabValue status;
Thanks!)
It was solved with following configuration:
#JoinFormula(value="SELECT v.ROW_ID FROM VOCAB v WHERE v.NAME=STATUS_ID AND v.TYPE='ACT_STAT'")
#ManyToOne
#NotFound(action = NotFoundAction.IGNORE)
private VocabValue status;
Thank's )
Suppose i want to have a composite key as street, city for purchase order entity.
Below is how i identify doing it,
#Embeddable
public class BillingAddress implements Serializable {
private String street;
private String city;
public BillingAddress(){
}
public BillingAddress(String street, String city) {
this.street = street;
this.city = city;
}
//with getters and setters
}
#Entity
#IdClass(BillingAddress.class)
public class PurchaseOrder {
public PurchaseOrder(BillingAddress billingAddress) {
street = billingAddress.getStreet();
city = billingAddress.getCity();
}
#Id
#AttributeOverrides({
#AttributeOverride(name = "street", column = #Column(name = "STREET")),
#AttributeOverride(name = "city", column = #Column(name = "CITY")) })
private String street;
private String city;
private String itemName;
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
}
I want to understand what is really #AttributeOverrides annotation do? Even i change to colomn name to something STREET1 i still see the table created with column name STREET. So what is column = #Column(name = "STREET")) doing here.
Also instead of constructore taking the BillingAddress i can have it like a field of PurchaseOrder class right like,
public class PurchaseOrder {
BillingAddress billingAddress;
}
In this case how this going to change?
Do i still need to have private String street; private String city; in PurchaseOrder?
Finally i read that using composite keys should be avoided in new data base system design which using composite primary key is applicable a situation where in order to map the legacy data base tables with out changing the data base table structure right? Is that statement a valid one?
//Edit question
Saving purchase order which billing address is in the field,
PurchaseOrder purchaseOrder = new PurchaseOrder();
purchaseOrder.setItemName("name");
BillingAddress billingAddress = new BillingAddress();
billingAddress.setCity("c1"); billingAddress.setStreet("s1"); purchaseOrder.setBillingAddress(billingAddress);
session.save(purchaseOrder);
There's are few question you asked, I tried to go through all of them and answer each one:
What does #AnnotationOverride do?
answer here: What does #AttributeOverride mean?
The second question is a bit unclear to me but I presume you're asking whether you have to include all the fields from the composite key in the PurchaseOrder class.
No, I don't think so. Here's an example I've put together real fast:
#Entity
#Table(name = "PURCHASE_ORDER")
public class PurchaseOrder{
#Id
private BillingAddress billingAddress;
//getters & setters
#Embeddable
public static class BillingAddress implements Serializable {
#Column(name = "street")
private String street;
#Column(name = "city")
private String city;
#Column(name = "itemName")
private String itemName;
//getters & setters
}
}
Don't worry about the syntax, just the structure. You can even add extra field into PurchaseOrder which isn't an id.
Should I use composite keys or not?
answer here: Should I use composite primary keys or not?
Well, your PurchaseOrder class does not extend from a mapped entity of any kind, and neither do the properties that you are (currently) applying the #AttributeOverrides to. So, there is nothing to actually override and your JPA provider is simply ignoring the annotations. What I think you are trying to do is define an embedded id for an entity, while overriding some of the column mappings for that id. You can do this with some modifications to your current code:
#Entity
public class PurchaseOrder {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "street", column = #Column(name = "BILLING_STREET")),
#AttributeOverride(name = "city", column = #Column(name = "BILLING_CITY")) })
private BillingAddress billingAddress;
private String itemName;
// Constructors, Getters/Setters
}
Note that I've changed the names of the overridden attributes, since with your current example, the embedded id name and overridden names are the same.
I'm new to hibernate. My problem is that I have an Oracle database. I have a view in the database. Now I want to use hibernate to retrieve data in that view. Is there any possible solutions?
Below Snippet can solve your problem, which has been extracted from the tutorial: Mapping Hibernate Entities to Views
Database Query
CREATE OR REPLACE VIEW cameron AS
SELECT last_name AS surname
FROM author
WHERE first_name = 'Cameron';
view entity
#Entity
#NamedNativeQuery(name = "findUniqueCameronsInOrder", query = "select * from cameron order by surname", resultClass = Cameron.class)
public class Cameron implements java.io.Serializable {
private static final long serialVersionUID = 8765016103450361311L;
private String surname;
#Id
#Column(name = "SURNAME", nullable = false, length = 50)
public String getSurname() {
return surname;
}
public void setSurname(final String surname) {
this.surname = surname;
}
}
Hibernate mapping file.
<mapping class="examples.hibernate.spring.query.domain.Cameron" />
finally some test !...
#Test
public void findTheCameronsInTheView() throws Exception {
final List<Cameron> camerons = findUniqueCameronsInOrder();
assertEquals(2, camerons.size());
final Cameron judd = camerons.get(0);
final Cameron mcKenzie = camerons.get(1);
assertEquals("Judd", judd.getSurname());
assertEquals("McKenzie", mcKenzie.getSurname());
}
A view is from accessing data nothing different from table, a problem arises when you want to add,update or delete from view.
Please read http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/querysql.html
It' very similar to mapping ordinary database table.
Create an Entity and use your view name as Table name.
#Entity
#Table(name = "rc_latest_offer_details_view")
public class OfferLatestDetailsViewEntity {
#Id
#Column(name = "FK_OFFER_ID")
private int offerId;
#Column(name = "MAX_CHANGED_DTM")
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime changedDateTime;
private BigDecimal price;
...
}
Then query for entities same way as you do for normal table.
Working in Hibernate 4, Spring 4.
we can achieve this by using # Immutable annotation in entity class to map database view with Hibernate
For example : I have created one database view user_data which have 2 columns (id and name) and mapped user_data view in the same way as database tables.
#Entity
#Table(name = "user_data")
#Immutable
public class UserView {
#Id
#Column(name = "ID")
private int ID ;
#Column(name = "NAME")
private String name ;
}
Recently i am started using hibernate. to insert or update i am using saveOrUpdate() function.
If i update an entry i works fine. But, with new entry hibernate generate a Query. Buts nothing gets updated in the table.
My scenario is like this,
i am using Many to One & One to Many relationship between two tables[Expense, Category]
For update or insert, i am creating two objects(Expense expense, Category category) from the
client side. In the server side, i set category object with expense object.
public void upDateExpenseTable(Expens expense, Category category) {
expense.setCategory(category);
Session session = Main.getSession();
try{
System.out.println("Inside Update Try Block");
session = Main.getSession();
Transaction tr = session.beginTransaction();
session.saveOrUpdate(expense);
tr.commit();
}
finally{
session.close();
}
}
Object structure is like, catogery.catId, category.catName &
expense.expnsId, expense.expnsName, expense.amount, expense.status, expense.userName.
But there is another one column in Expense Table cat_id. Its is through mapping annotation. But i dont have any property for that in Expense entity.
When inserting new data, i am not giving any Id.
Any suggestions!!!
public class Expens implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int expnsId;
private int amount;
private String date;
private String status;
private String userName;
#ManyToOne
#JoinColumn(name = "cat_id")
private Category category;
//Setter Getter
}
Category Classs
public class Category{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int catId;
private String catName;
#OneToMany(targetEntity=Expens.class, mappedBy = "category", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
private List<Expens> expenses;
}//Setters Getters ommited.
I'm not sure I understood everything but I can at least tell you that you're not building your bi-directional association correctly, you need to set "both sides of the link" when building your object graph:
...
expense.setCategory(category);
category.getExpenses().add(expense);
...
session.saveOrUpdate(category);
And this is usually done in "link management" methods, like this (in Category):
#Entity
public class Category {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private int catId;
private String catName;
#OneToMany(targetEntity=Expens.class, mappedBy = "category", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
private List<Expens> expenses = new ArrayList<Expens>();
public void addToExpenses(Expense expense) {
expenses.add(expense);
expense.setCategory(this);
}
protected List getExpenses() { // protected to prevent direct access from outside the hierarchy
return expenses;
}
protected void setExpenses(List expenses) { // protected to prevent direct access
this.expenses = expenses;
}
//...
}
And the code becomes:
category.addToExpenses(expense);
session.saveOrUpdate(category);
Funnily enough (or not), I've written about this three times today.
Resource
Hibernate Core Documentation
1.2.6. Working bi-directional links