I have an Entity in my hibernate 4.2.6 java application as follow:
#Entity
public class Store {
#ElementCollection(fetch=FetchType.EAGER)
List<String> fields = new ArrayList<>();
/* Getter and Setter */
}
Store Table hase one record and For this record, I add two String field. I get all record of table as follow:
return sesseionFactory.getCurrentSession.createCriteria(Store.class).list()
But It return two record!. When I add 3 String filed, it return three record.
Where is problem?
Related
I'm trying to add a Map entity in two ways:
Map<Enum,Enum>:
#Entity
#Table(name = "reservations")
public class Reservation {
...
private Map<Request, RequestImportance> guestsRequests;
...
}
Map<Enum,Boolean>:
public class Room {
...
private Map<Request, Boolean> requestsMap;
}
These are the enums Request and RequestImportance:
public enum Request {
ELEVATORPROXIMITY,
SEAVIEW,
BATHTUB,
BALCONY,
HANDICAPPED,
HIGHFLOOR
}
public enum RequestImportance {
NOT_IMPORTANT,
NICE_TO_HAVE,
MUST;
}
I'm not sure which attributes I'm supposed to use to map to the DB.
I'm using mySQL for this project.
EDIT:
Probably not possible to do that. I figured that I would change the Map to a List and create a new Class which contains an Enum field. That way I can represent the data in the DB.
You could use #ElementCollection for that
#ElementCollection
private Map<Request, RequestImportance> guestsRequests = new HashMap<>();
By default it is mapped to the table reservation_guests_requests that has three columns
reservation_id (refers to Reservation obviously)
guests_requests_key (contains Request ordinal number)
guests_requests (contains RequestImportance ordinal number)
If you are not fine with these names or need to fit the existing table they could be adjusted
#ElementCollection
#CollectionTable(
name = "guests_requests",
joinColumns = #JoinColumn(name = "rsrv_id")
)
#MapKeyColumn(name = "request_n")
#Column(name = "request_importance_n")
private Map<Request, RequestImportance> guestsRequests = new HashMap<>();
This time it will be guests_requests with
rsrv_id (I guess reservation_id is a better name, just showed the possibility to adjust it)
request_n
request_importance_n
On the one hand saving enum ordinal is fine, on the other hand it is sensitive to its order and could make issues if the values are reordered.
Luckily it could be switched to String or any custom index or an abbreviation with AttributeConverter. If you put #Enumerated(EnumType.STRING) above the map it will affect only the value i.e. RequestImportance
I am setting up criteria for database calls and am having trouble getting understanding how to set up my code. I have put my criteria in and now need to know how I make sure I populate the variables right. This is what I have.
Public class Key extends abstractDAO<key>{
Public List<Key> getKeyValues(){
Criteria c = createCriteria();
c.add(Restrictions.lt("id", 3)).addOrder(Order.asc("id")).list();
return c.list();
Now the table has 2 rows. One is current and the second is a new request row. The database has 3 columns. Column 1 is the I'd, column two is the key, and 3 is a timestamp. I need to populate all the variables in order. I am not sure how to go about this in my key.java file
Key.java
#column(name="id")
private int actualID;
#column(name="key")
private Boolean actualKey;
#column (name="actualTime")
private Date actualTime;
Then repeats with requested, requestKey, and requestTime. Then I have public get and sets for each. Have not added any parameters to any method yet either. I am not sure how to set this file up so the list actually sets the variables when the DAO request the rows of the database.
try the following:
public List<Key> getKeyValues()
{
return createCriteria()
.add( Restrictions.lt( "actualID", 3 ) )
.addOrder( Order.asc( "actualID" ) )
.list();
}
Provided that the rest of the mapping and the implementation of createCriteria() are correct, it should return a list of Key's objects whose ids are less than 3, ordered by id.
I want to store emailIds that needs to be notified when a change happens into a table.
I only have one table with columns ownerid and emailid. I want to store emailid in separate rows, rather than a comma separated list. I don't need a owner table, because i dont have any other information for the owner. I just want to save the emailids, but into separate rows.
how do i do that in hibernate.
I tried using something like this
#Table(name = "OwnerEmailIds")
#Entity
public class OwnerEmailIds implements Serializable {
private static final long serialVersionUID = 5906661729869048121L;
#Column(name = "OwnerID", nullable = false)
private String ownerId;
#ElementCollection(fetch=FetchType.EAGER) // must use eager as we close the session before returning
#CollectionTable(name="OwnerEmailIds", joinColumns=#JoinColumn(name="vendorId"))
#Column(name = "emailId")
private Set<String> EmailIds = new HashSet<String>();
But problem here is my collection table is same as the entity table.
And as my emailIds column in not null, when i try to save the object it fails with sql error stating emailid column can't be null.
To be able to map an entity to a table, Hibernate requires a unique id property, that maps to a unique (primary) key on the table.
As you have stated that you don't have this and if this is the only table your application is using, then Hibernate might not be the best choice.
You could still get the required information through Hibernate from your database by executing a native SQL query:
SQLQuery q = session.createSQLQuery("select OwnerID from OwnerEmailIds where emailId = :email");
q.setScalar("OwnerID", StandardBasicTypes.LONG);
q.setParameter("email", emailId)
List<Long> ids = (List<Long>) q.list();
Storing the ids could also be done with a native query, but here you would have to take into account data that is already there, so it is a little harder.
I think what you are asking for is to put collection in multiple rows and repeat other values, in you case email list will be inserted and owner_id will repeated for it's emails.
Hibernate does not provide any configuration for that. You have to do it manually.
You can do what you are looking for using the following structure and code. You must have a primary key, here you can make your email id as primary key or you can add an autoincrement integer id.
#Table(name = "OwnerEmailIds")
#Entity
public class OwnerEmailIds implements Serializable {
private static final long serialVersionUID = 5906661729869048121L;
#Column(name = "OwnerID", nullable = false)
private String ownerId;
#Id
#Column(name = "emailId")
private String emailId;
//setter and getters
}
Then you iterate through the list of email ids and create the below object and then save them individually. You can not create a collection object and configure hibernate to store them in the current table in multiple rows.
//loop throught the list of email ids
OwnerEmailIds oei = new OwnerEmailIds();
oei.setOwnerId("first last name");
oei.setEmailId("some#somedomain.com");
session.save(oei);
If you make emailId as primary key then you will have to make sure that no two owners has same email id. If that is the case then you have to add another auto_increment primary key.
Scenario: Hibernate 3.6 with xml-based mapping, Java7, Postgresql 8.3.
I'm currently refactoring an application where I have got this scenario for the database:
main_table
id integer
other_field string
(id) PK
secondary_table
other_field string
value string
(other_field, value) PK
Basically, there's a secondary table which contains an "other_field" which is matched on the main table; I need to extract all values for a certain record in main_table and map them.
In SQL I'd use a query like:
SELECT value FROM secondary table INNER JOIN main_table ON secondary_table.other_field == main_table.other_field where main_table.id = 1;
But I don't understand how to map a collection of basic types (strings) to the Main object in Java using such a query (or a similar one if the one I propose is not hibernate friendly), so that I can have a "values" property on my mapped object, which should be a Set<String>
I think this is what you are looking for:
#Entity
public class Primary { // Main table
#Id
#Column(name="EMP_ID")
private long id;
...
#ElementCollection
#CollectionTable(
name="PRIMARY_SECONDARY",
joinColumns=#JoinColumn(name="PRIMARY_ID")
)
private Set<Secondary> phones;
...
}
#Embeddable
public class Secondary { // Secondary table
private String value;
...
}
Full example and further details.
I export data from MS SQLServer to an xml file, then use that dataset in running unit tests that require database. I use dbunit maven plugin for it.
Unfortunately for me, not all columns in some tables are mapped in my Entity classes.
As an example, say, we have a table called 'member'.
Member table has three columns: memberid, membername, memberrank.
When I do an export, I get all three columns exported.
But in my MemberEntity class, I only map memberid and membername, because I do not need memberrank in my application. So I would have the MemberEntity looking like this:
#Entity
#Table(name = "member")
public class MemberEntity {
#Id
#GeneratedValue()
#Column(name = "memberid", nullable = false)
private Integer memberid;
#Column(name = "membername", nullable = false)
private String membername;
...
}
Then, I try to insert dataset into HSQLDB before a test case:
IDatabaseConnection conn = new DatabaseConnection(((SessionImpl) (entityManager.getDelegate())).connection());
IDataSet dataset = new XmlDataSet(
resourceLoader.getResource("classpath:dataset.xml").getInputStream());
conn.getConfig().setProperty("http://www.dbunit.org/properties/datatypeFactory", new MsSqlDataTypeFactory());
DatabaseOperation.CLEAN_INSERT.execute(conn, dataset);
At this point, I get an exception saying the column MemberRank does not exist. It says something like the following:
org.dbunit.dataset.NoSuchColumnException: MEMBER.MEMBERRANK - (Non-uppercase input column: memberrank) in ColumnNameToIndexes cache map. Note that the map's column names are NOT case sensitive.
When I remove the column from the dataset, all is well. If I add in the memberRank mapping to my Entity class, again, all goes well.
But I cannot add the column mapping into my Entity class. Is there an easy way (other than removing the column and the associated data from the exported dataset manually) of excluding that column from being (attempted to be) added in when I do INSERT?
In hibernate every non static non transient property (field or method depending on the access type) of an entity is considered persistent, unless you annotate it as #Transient.
for example,
#Transient
public int counter; //transient property
private String firstname; //persistent property
The methods and fields annotated as #Transient will be ignored by the entity manager.See here for more information.
Maybe this answer comes a little bit late, but I've just run into a similar problem and wrote the following method to solve it (I'm using dbUnit 2.5.0). Hope it helps somebody.
/**
* Generates a new data set with the columns declared in the
* "excludedColumns" map removed.
*
* #param src
* Source data set.
* #param excludedColumns
* Map of table names and column names. Columns in this map are
* removed in the resulting data set.
* #return Data set with the columns declared in the "excludedColumns" map
* removed. Tables that are not specified in the "excludedColumns"
* map are left untouched.
* #throws DataSetException
*/
public static IDataSet filterDataSet(IDataSet src,
Map<String, Set<String>> excludedColumns) throws DataSetException {
if (excludedColumns == null) {
return src;
}
ArrayList<ITable> tables = new ArrayList<ITable>(
src.getTableNames().length);
for (String tableName : src.getTableNames()) {
if (excludedColumns.containsKey(tableName)) {
ITable filteredTable = DefaultColumnFilter
.excludedColumnsTable(
src.getTable(tableName),
excludedColumns.get(tableName).toArray(
new String[0]));
tables.add(filteredTable);
} else {
tables.add(src.getTable(tableName));
}
}
return new DefaultDataSet(tables.toArray(new ITable[0]),
src.isCaseSensitiveTableNames());
}
The core of the method is DefaultColumnFilter. I'm using a commodity static method here, but an instance of DefaultColumnFilter gives a lot of flexibility.
I wonder if there is a more straight forward way of doing this.