Exception when trying to use DynamoDBMapper: no mapping for HASH key - database

I have a DynamoDB table with a primary key (id : integer) and secondary key (dateTo : String). I've made a Class that utilizes DynamoDBMapper:
#DynamoDBTable(tableName="MyItems"
public class MyItemsMapper {
private int id;
private String dateTo;
private String name;
#DynamoDBHashKey(attributeName="id")
public void setId(int id) { this.id = id; }
public int getId() { return id; }
#DynamoDBAttribute(attributeName="dateTo")
public void setDateTo(String dateTo) { this.dateTo = dateTo; }
public String getDateTo() { return dateTo; }
#DynamoDBAttribute(attributeName="name")
public void setName(String name { this.name = name; }
public String getName() { return name; }
public boolean saveItem(MyItemsMapper item) {
try {
DynamoDBMapper mapper = new DynamoDBMapper(client); //<-- This connects to the DB. This works fine.
item.setId(generateUniqueNumber()); //<-- This generates a unique integer. Also seems to work fine.
mapper.save(item);
logger.info("Successfully saved item. See info below.");
logger.info(item.toString());
return true;
} catch (Exception e) {
logger.error("Exception while trying to save item: " + e.getMessage());
e.printStackTrace();
return false;
}
}
}
I then have a manager class that uses the bean above, like so:
public class MyManager {
public boolean recordItem(
int id,
String dateTo,
String name,
) {
MyItemsMapper myItemsMapper = new MyItemsMapper();
myItemsMapper.setId(id);
myItemsMapper.setDateTo(dateTo);
myItemsMapper.setName(name);
myItemsMapper.saveItem(myItemsMapper);
}
}
I am running the manager class in a JUnit test:
public class MyManagerTest {
#Test
public void saveNewItemTest() {
MyManager myManager = new MyManager();
myManager.recordItem(1234567, "2018-01-01", "Anthony");
}
}
When I use the saveItem method above via my manager by running my JUnit test, I get the following error:
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: MyItemsMapper; no mapping for HASH key
Not really sure what it's pertaining to, as I definitely have a primary key for my table and my secondary key always has a value as well.
How do I get this to work?
More Info:
It's worth noting that I can record data into my DynamoDB table via the Item object. If I do the below, my data gets recorded into the database:
DynamoDB dynamoDB = new DynamoDBClient().connectToDynamoDB(); //<--
Connection. Works fine.
Table table = dynamoDB.getTable("MyItems");
item.withPrimaryKey("id", 1234567);
item.withString("dateTo", "2018-01-01");
item.withString("name", "Anthony");
PutItemOutcome outcome = table.putItem(item);
However, I'm trying to use DynamoDBMapper because I'm reading that it is a more organized, better way to access data.

Im not sure if this is causing the problem, but you are creating the myItemsMapper object, then passing a reference to this object to itself.
I would suggest removing your saveItem method. The MyItemsMapper class should be a plain old java object. Then make MyManager like this
public class MyManager {
public boolean recordItem(
int id,
String dateTo,
String name,
) {
MyItemsMapper myItemsMapper = new MyItemsMapper();
myItemsMapper.setId(id);
myItemsMapper.setDateTo(dateTo);
myItemsMapper.setName(name);
DynamoDBMapper mapper = new DynamoDBMapper(client);
mapper.save(myItemsMapper);
}
}
If you particularly want to keep the saveItem method make it like this
public boolean saveItem() {
try {
DynamoDBMapper mapper = new DynamoDBMapper(client);
mapper.save(this);
logger.info("Successfully saved item. See info below.");
logger.info(this.toString());
return true;
} catch (Exception e) {
logger.error("Exception while trying to save item: " + e.getMessage());
e.printStackTrace();
return false;
}
}
And then in MyManager do
MyItemsMapper myItemsMapper = new MyItemsMapper();
myItemsMapper.setId(id);
myItemsMapper.setDateTo(dateTo);
myItemsMapper.setName(name);
myItemsMapper.saveItem();

Related

Tableview update database on edit

So the thing that i want to happen, is making the tableview update the data in the database after editing it. I wanted to use the SetOnEditCommit method here. The cell editing does work, but it never gets updated, with no error either. In the first place im a bit clueless if this method is actually efficient (probably not), since its hard to find some sources for this specific thing. And the sources that i found weren't really helpful. So it would be nice if someone had an idea as to why it doesn't update, or maybe provide an alternate option here.
The mentioned part:
columnType.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<UserDetails, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<UserDetails, String> event) {
updataData();
}
});
tableview.setItems(null);
tableview.setItems(data);
}
public void updataData() {
Connection connection = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://37.128.148.113:3306/FYS", "FYS", "Kcj8g87~");
Statement con = connection.createStatement();
//connection
TablePosition pos = tableview.getSelectionModel().getSelectedCells().get(0);
int row = pos.getRow();
TableColumn col = pos.getTableColumn();
String data1 = (String) col.getCellObservableValue(row).getValue();
//cell
UserDetails row1 = tableview.getSelectionModel().getSelectedItem();
c1 = row1.getId();
//row
//tableview variables
con.execute("UPDATE gevonden_bagage SET type = 'data1' WHERE koffer_id = 'c1' ");
//Query
} catch (SQLException ex) {
System.err.println("Error" + ex);
}
}
//get connection, get celldata, get id data from first row, update cell with selected id
full controller class:
package simple;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
/**
*
* #author admin
*/
public class FXMLUserController extends SimpleController implements Initializable {
#FXML
public TableView<UserDetails> tableview;
#FXML
public TableColumn<UserDetails, String> columnId;
#FXML
public TableColumn<UserDetails, String> columnType;
#FXML
public TableColumn<UserDetails, String> columnKleur;
#FXML
public TableColumn<UserDetails, String> columnLuchthaven;
#FXML
public TableColumn<UserDetails, String> columnKenmerken;
#FXML
public TableColumn<UserDetails, String> columnStatus;
#FXML
public TableColumn<UserDetails, String> columnDatum;
#FXML
private Button btnLoad;
//declare observable list for database data
private ObservableList<UserDetails> data;
private DbConnection dc;
String c1;
#FXML
//strings for getRow method
#Override
public void initialize(URL url, ResourceBundle rb) {
dc = new DbConnection();
loadDataFromDatabase();
}
#FXML
public void loadDataFromDatabase() {
try {
Connection conn = dc.Connect();
data = FXCollections.observableArrayList();
// Execute query and store result in a resultset
ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM gevonden_bagage");
while (rs.next()) {
//get strings
data.add(new UserDetails(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5),
rs.getString(6), rs.getString(7)));
}
} catch (SQLException ex) {
System.err.println("Error" + ex);
}
//Set cell values to tableview.
tableview.setEditable(true);
tableview.getSelectionModel().setCellSelectionEnabled(true);
columnType.setCellFactory(TextFieldTableCell.forTableColumn());
columnKleur.setCellFactory(TextFieldTableCell.forTableColumn());
columnLuchthaven.setCellFactory(TextFieldTableCell.forTableColumn());
columnKenmerken.setCellFactory(TextFieldTableCell.forTableColumn());
columnStatus.setCellFactory(TextFieldTableCell.forTableColumn());
columnDatum.setCellFactory(TextFieldTableCell.forTableColumn());
//makes columns editable
columnId.setCellValueFactory(new PropertyValueFactory<>("id"));
columnType.setCellValueFactory(new PropertyValueFactory<>("type"));
columnKleur.setCellValueFactory(new PropertyValueFactory<>("kleur"));
columnLuchthaven.setCellValueFactory(new PropertyValueFactory<>("luchthaven"));
columnKenmerken.setCellValueFactory(new PropertyValueFactory<>("kenmerken"));
columnStatus.setCellValueFactory(new PropertyValueFactory<>("status"));
columnDatum.setCellValueFactory(new PropertyValueFactory<>("datum"));
columnType.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<UserDetails, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<UserDetails, String> event) {
updataData();
}
});
tableview.setItems(null);
tableview.setItems(data);
}
public void updataData() {
Connection connection = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://37.128.148.113:3306/FYS", "FYS", "Kcj8g87~");
Statement con = connection.createStatement();
//connection
TablePosition pos = tableview.getSelectionModel().getSelectedCells().get(0);
int row = pos.getRow();
TableColumn col = pos.getTableColumn();
String data1 = (String) col.getCellObservableValue(row).getValue();
//cell
UserDetails row1 = tableview.getSelectionModel().getSelectedItem();
c1 = row1.getId();
//row
//tableview variables
con.execute("UPDATE gevonden_bagage SET type = 'data1' WHERE koffer_id = 'c1' ");
//Query
} catch (SQLException ex) {
System.err.println("Error" + ex);
}
}
//get connection, get celldata, get id data from first row, update cell with selected id
#FXML
public void getRow() {
TablePosition pos = tableview.getSelectionModel().getSelectedCells().get(0);
int row = pos.getRow();
TableColumn col = pos.getTableColumn();
// this gives the value in the selected cell:
String data1 = (String) col.getCellObservableValue(row).getValue();
System.out.println(data1);
//CURRENTLY UNUSED METHOD
}
}
Model class:
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
*
* #author admin
*/
public class UserDetails {
private final StringProperty id;
private final StringProperty type;
private final StringProperty kleur;
private final StringProperty luchthaven;
private final StringProperty kenmerken;
private final StringProperty status;
private final StringProperty datum;
//Default constructor
public UserDetails(String id, String type, String kleur, String luchthaven, String kenmerken, String status, String datum) {
this.id = new SimpleStringProperty(id);
this.type = new SimpleStringProperty(type);
this.kleur = new SimpleStringProperty(kleur);
this.luchthaven = new SimpleStringProperty(luchthaven);
this.kenmerken = new SimpleStringProperty(kenmerken);
this.status = new SimpleStringProperty(status);
this.datum = new SimpleStringProperty(datum);
}
//getters
public String getId() {
return id.get();
}
public String getType() {
return type.get();
}
public String getKleur() {
return kleur.get();
}
public String getLuchthaven() {
return luchthaven.get();
}
public String getKenmerken() {
return kenmerken.get();
}
public String getStatus() {
return status.get();
}
public String getDatum() {
return datum.get();
}
//setters
public void setId(String value) {
id.set(value);
}
public void setType(String value) {
type.set(value);
}
public void setKleur(String value) {
kleur.set(value);
}
public void setLuchthaven(String value) {
luchthaven.set(value);
}
public void setKenmerken(String value) {
kenmerken.set(value);
}
public void setStatus(String value) {
status.set(value);
}
public void setDatum(String value) {
datum.set(value);
}
//property values
public StringProperty idProperty() {
return id;
}
public StringProperty typeProperty() {
return type;
}
public StringProperty kleurProperty() {
return kleur;
}
public StringProperty luchthavenProperty() {
return luchthaven;
}
public StringProperty kenmerkenProperty() {
return kenmerken;
}
public StringProperty statusProperty() {
return status;
}
public StringProperty datumProperty() {
return datum;
}
}
From the TableView documentation:
By default the TableColumn edit commit handler is non-null, with a
default handler that attempts to overwrite the property value for the
item in the currently-being-edited row. It is able to do this as the
Cell.commitEdit(Object) method is passed in the new value, and this is
passed along to the edit commit handler via the CellEditEvent that is
fired. It is simply a matter of calling
TableColumn.CellEditEvent.getNewValue() to retrieve this value.
It is very important to note that if you call
TableColumn.setOnEditCommit(javafx.event.EventHandler) with your own
EventHandler, then you will be removing the default handler. Unless
you then handle the writeback to the property (or the relevant data
source), nothing will happen.
So the problem is that by setting the onEditCommit on columnType, you remove the default handler that actually updates typeProperty in the UserDetails instance. Consequently
String data1 = (String) col.getCellObservableValue(row).getValue();
gives the old value, and your update to the database won't change anything.
Additionally, you have errors in the way you create the SQL statement. You are making the id in the WHERE clause the literal value 'c1' (instead of the value contained in the variable c1, and similarly setting the value of type to the literal value 'data1', instead of the value in the variable data1.
Here is a fix, along with some simplification of the code and some better practices for avoiding SQL injection attacks:
columnType.setOnEditCommit(event -> {
UserDetails user = event.getRowValue();
user.setType(event.getNewValue());
updateData("type", event.getNewValue(), user.getId());
});
and then
private void updateData(String column, String newValue, String id) {
// btw it is way better to keep the connection open while the app is running,
// and just close it when the app shuts down....
// the following "try with resources" at least makes sure things are closed:
try (
Connection connection = DriverManager.getConnection("jdbc:mysql://37.128.148.113:3306/FYS", "FYS", "Kcj8g87~");
PreparedStatement stmt = connection.prepareStatement("UPDATE gevonden_bagage SET "+column+" = ? WHERE koffer_id = ? ");
) {
stmt.setString(1, newValue);
stmt.setString(2, id);
stmt.execute();
} catch (SQLException ex) {
System.err.println("Error");
// if anything goes wrong, you will need the stack trace:
ex.printStackTrace(System.err);
}
}

Too many entity_writes when creating multiple entities in cloud datastore

I am noticing a weird(?) behavior when I am creating a large number of entities (about 1000) in my datastore.
I have a REST method which creates 1000 entities of same kind. I am using
datastore.put(entityObject);
to create entities. When I check the trace timeline I see this:
If I check details of every subsequent put call it shows this:
And there are a ton of these put calls! Even the 'Insights' tab says:
Here is my entity class:
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Index;
import com.sm.task.entity.Task;
#Entity(name = "TMS.Task")
public class TaskEntity {
#Id
private String id;
private String title;
private String description;
#Index
private String status;
public Task toTask() {
return new Task(
id,
title,
description,
status);
}
public Key<TaskEntity> key() {
return Key.create(TaskEntity.class, id);
}
public static Key<TaskEntity> keyFor(String id) {
return Key.create(TaskEntity.class, id);
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
I didn't find any setting which causes or controls this behavior. Can anyone please help me understand the reason of this issue and how to get rid of it?
Instead of making 1,000 putcalls to store 1,000 entities, you should make 2 put calls with 500 entities in each (just pass a list of entities to be saved). This is way faster and more efficient.

Trouble persisting one-to-many relationship using jpa in Google app engine

I have two entities as below and when i try to persist "Category" the "Tip" object list does not get persisted .I noticed that in my DAO class that I was able to see the category object with tipsForCategory list of size 1 but when i try to retrieve after persisting I am able to see only Category details and tipsForCategory comes as empty list.
#Entity
public class Category {
#GeneratedValue
#Id
public Long id;
#Column
public String categoryName;
#OneToMany(mappedBy = "category",cascade = {CascadeType.ALL})
public List<Tip> tipsForCategory;
public Long getId() { return id; }
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName.toLowerCase();
}
public void addTip(Tip tip) {
if(!tipsForCategory.contains(tip)) {
tipsForCategory.add(tip);
}
}
public List<Tip> getTipsForCategory() {
return tipsForCategory;
}
}
Code for Tip Entity
#Entity
public class Tip {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Key key;
#Column
public String tipDescription;
#ManyToOne(cascade = {CascadeType.ALL})
public Category category;
public String getTipDescription() {
return tipDescription;
}
public void setTipDescription(String tipInformation) {
this.tipDescription = tipInformation;
}
}
Code for persisting in my DAO
#Override
#Transactional
public void save(Category category) {
EntityManager localEntityManager=entityManager.getEntityManagerFactory().createEntityManager();
EntityTransaction transaction=localEntityManager.getTransaction();
try {
transaction.begin();
localEntityManager.persist(category);
localEntityManager.flush();
transaction.commit();
}catch (Exception e) {
e.printStackTrace();
localEntityManager.close();
}
}
My retrieval method is
#Override
public CategoryDTO findCategory(Long categoryId) throws FixitException{
CategoryDTO categoryDTO=null;
Category category=categoryDAO.findById(categoryId);
if(category!=null) {
categoryDTO=new CategoryDTO(category);
}
return categoryDTO;
}
#Override
public List<TipDTO> retrieveTips(Long categoryId) throws FixitException{
List<TipDTO> tips=null;
try {
CategoryDTO category = findCategory(categoryId);
if (category != null) {
tips = category.getTipsForCategory();
}
}
catch(Exception e)
{
throw new FixitException(FixitConstants.TIP_RETRIEVAL_ERROR+categoryId,e.getCause());
}
return tips;
}
Looks like the problem was with lazy fetch I just resolved the same.In my categoryDAO.findById(..) code I had to add an additional line to retrieve the tips as below
#Override
public Category findById(Long categoryId) {
Category category=null;
try {
TypedQuery<Category> findByCategoryId = entityManager.createQuery("Select cat from Category cat where cat.id=:categoryId",Category.class);
category=findByCategoryId.setParameter("categoryId", categoryId).getSingleResult();
}
catch (Exception e)
{
e.printStackTrace();
}
*** int tipsSize=category.getTipsForCategory().size();***
return category;
}

Spring AOP - Database Auditing

I'm using Spring AOP trying to define a good approach to have all my tables audited with no much hassle. Example of scenario:
I have a table named Person and its respective table PersonLog, which will store the Person values in addition to the user who modified, when and the type of the event, for each update.
Simply put, my question is:
I'm trying to come up with a way that my advice class would be smart enough to handle any new table being audited without any needed modification to it... let's say that I created the table Car and its CarLog table, if I could avoid the need to change anything in my advice implementation (it would automatically identify Car as being audited and would be able to persist a CarLog entity) ---> I can identify table Car as being audited pretty easily (by annotation), but I'm struggling to find a way to create and persist a CarLog instance dynamically.
Can anyone think of a way to accomplish that? Thanks.
This is called "change data capture" or CDC.
Personally, I don't think this is a good use for Spring or AOP. I think it would be better done in the database itself, especially if the database is shared/modified by more than one application.
You don't say which database you're using, but I'd recommend digging into your vendor's docs to find out what they have out of the box to support CDC.
i had similiar requirement in project where i am suppose to take snapshot of complex object graph before saving.
solution i have applied is 1) developed custom annotation #Archivable with certain attribute like nullify,ignore, orignal, setArchiveFlag
2) written hiberante deep cloner utility which create replica of object and insert into same table. deep cloner works on simple trick searlize and then desearlize object this will create new instances and then set id and version to null.
3) used cloner utility in entity interceptor to take decision weather to archive or not.
below is some of that code.
#Retention(RetentionPolicy.RUNTIME)
#Target( { ElementType.TYPE })
public #interface Archivable {
/** This will mark property as null in clone */
public String[] nullify() default {};
/**
* If property is archivable but not from enclosing entity then specify as
* ignore.
*/
public String[] ignore() default {};
/**
* sets original reference to clone for back refer data. This annotation is
* applicable to only root entity from where archiving started.
*
* #return
*/
public String original() default "";
/**
* if marks cloned entity to archived, assumes flag to be "isArchived".
* #return
*/
public boolean setArchiveFlag() default false;
}
#Component
public class ClonerUtils {
private static final String IS_ARCHIVED = "isArchived";
#Autowired
private SessionFactory sessionFactory;
public Object copyAndSave(Serializable obj) throws Exception {
List<BaseEntity> entities = new ArrayList<BaseEntity>();
Object clone=this.copy(obj,entities);
this.save(clone, entities);
return clone;
}
public Object copy(Serializable obj,List<BaseEntity> entities) throws Exception{
recursiveInitliaze(obj);
Object clone = SerializationHelper.clone(obj);
prepareHibernateObject(clone, entities);
if(!getOriginal(obj).equals("")){
PropertyUtils.setSimpleProperty(clone, getOriginal(obj), obj);
}
return clone;
}
private void save(Object obj,List<BaseEntity> entities){
for (BaseEntity baseEntity : entities) {
sessionFactory.getCurrentSession().save(baseEntity);
}
}
#SuppressWarnings("unchecked")
public void recursiveInitliaze(Object obj) throws Exception {
if (!isArchivable(obj)) {
return;
}
if(!Hibernate.isInitialized(obj))
Hibernate.initialize(obj);
PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
for (PropertyDescriptor propertyDescriptor : properties) {
Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
if (origProp != null && isArchivable(origProp) && !isIgnore(propertyDescriptor, obj)) {
this.recursiveInitliaze(origProp);
}
if (origProp instanceof Collection && origProp != null) {
for (Object item : (Collection) origProp) {
this.recursiveInitliaze(item);
}
}
}
}
#SuppressWarnings("unchecked")
private void prepareHibernateObject(Object obj, List entities) throws Exception {
if (!isArchivable(obj)) {
return;
}
if (obj instanceof BaseEntity) {
((BaseEntity) obj).setId(null);
((BaseEntity) obj).setVersion(null);
if(hasArchiveFlag(obj)){
PropertyUtils.setSimpleProperty(obj, IS_ARCHIVED, true);
}
entities.add(obj);
}
String[] nullifyList = getNullifyList(obj);
for (String prop : nullifyList) {
PropertyUtils.setProperty(obj, prop, null);
}
PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
for (PropertyDescriptor propertyDescriptor : properties) {
if (isIgnore(propertyDescriptor, obj)) {
continue;
}
Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
if (origProp != null && isArchivable(origProp)) {
this.prepareHibernateObject(origProp, entities);
}
/** This code is for element collection */
if(origProp instanceof PersistentBag){
Collection elemColl=createNewCollection(origProp);
PersistentBag pColl=(PersistentBag) origProp;
elemColl.addAll(pColl.subList(0, pColl.size()));
PropertyUtils.setSimpleProperty(obj, propertyDescriptor.getName(), elemColl);
continue;
}
if (origProp instanceof Collection && origProp != null) {
Collection newCollection = createNewCollection(origProp);
PropertyUtils.setSimpleProperty(obj, propertyDescriptor.getName(), newCollection);
for (Object item : (Collection) origProp) {
this.prepareHibernateObject(item, entities);
}
}
}
}
#SuppressWarnings("unchecked")
private Collection createNewCollection(Object origProp) {
try {
if(List.class.isAssignableFrom(origProp.getClass()))
return new ArrayList((Collection)origProp);
else if(Set.class.isAssignableFrom(origProp.getClass()))
return new HashSet((Collection)origProp);
else{
Collection tempColl=(Collection) BeanUtils.cloneBean(origProp);
tempColl.clear();
return tempColl;
}
} catch (Exception e) {
e.printStackTrace();
}
return new ArrayList();
}
private boolean isIgnore(PropertyDescriptor propertyDescriptor,Object obj){
String propertyName=propertyDescriptor.getName();
String[] ignores=getIgnoreValue(obj);
return ArrayUtils.contains(ignores, propertyName);
}
private String[] getIgnoreValue(Object obj) {
String[] ignore=obj.getClass().getAnnotation(Archivable.class).ignore();
return ignore==null?new String[]{}:ignore;
}
private String[] getNullifyList(Object obj) {
String[] nullify=obj.getClass().getAnnotation(Archivable.class).nullify();
return nullify==null?new String[]{}:nullify;
}
public boolean isArchivable(Object obj) {
return obj.getClass().isAnnotationPresent(Archivable.class);
}
private String getOriginal(Object obj) {
String original=obj.getClass().getAnnotation(Archivable.class).original();
return original==null?"":original;
}
private boolean hasArchiveFlag(Object obj) {
return obj.getClass().getAnnotation(Archivable.class).setArchiveFlag();
}
#SuppressWarnings({ "unchecked", "unused" })
private Collection getElemColl(Object obj, Object origProp) {
Collection elemColl=createNewCollection(origProp);
for (Object object : (Collection)origProp) {
elemColl.add(object);
}
return elemColl;
}
#SuppressWarnings("unused")
private boolean isElementCollection(Object obj, String name) {
try {
Annotation[] annotations=obj.getClass().getDeclaredField(name).getAnnotations();
for (Annotation annotation : annotations) {
if(annotation.annotationType() == ElementCollection.class)
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
Envers is what you require for auditing purposes

App Engine JPA Datastore delete entity

im trying to build a google app engine projekt with JPA, JAX-RS and JAX-B. My POST and GET Methods work, but my DELETE method doesn't delete the data.
Resource
#DELETE
#Path("card/{id}")
public void deleteCardById (#PathParam ("id") Long id) {
Service.removeCard(id);
}
Service
public static void removeCard(Long id) {
EntityManager em = EMFService.get().createEntityManager();
Card emp = findCard(id);
if (emp != null) {
em.remove(emp);
}
em.close();
}
public static Card findCard(Long id) {
EntityManager em = EMFService.get().createEntityManager();
Card card = em.find(Card.class, id);
em.close();
return card;
}
Entity
#XmlRootElement
#Entity
public class Card {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
String begriff;
String tabu1;
String tabu2;
String tabu3;
public Card(String begriff, String tabu1, String tabu2, String tabu3) {
super();
Begriff = begriff;
Tabu1 = tabu1;
Tabu2 = tabu2;
Tabu3 = tabu3;
}
public Card() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getBegriff() {
return Begriff;
}
public void setBegriff(String begriff) {
Begriff = begriff;
}
public String getTabu1() {
return Tabu1;
}
public void setTabu1(String tabu1) {
Tabu1 = tabu1;
}
public String getTabu2() {
return Tabu2;
}
public void setTabu2(String tabu2) {
Tabu2 = tabu2;
}
public String getTabu3() {
return Tabu3;
}
public void setTabu3(String tabu3) {
Tabu3 = tabu3;
}
#Override
public String toString() {
return "Card [Begriff=" + Begriff + ", Tabu1=" + Tabu1 + ", Tabu2="
+ Tabu2 + ", Tabu3=" + Tabu3 + "]";
}
When i Debug the app it gives the correct Object to the remove function. But it just don't remove the data ...
You mean you're using v1 of the GAE JPA plugin, and you don't bother putting a transaction around your remove (so the remove is delayed until the next transaction ... which never happens)?
Obviously you could either put a transaction around the remove, or better still you use v2 of the GAE JPA plugin
I was facing similar issue too. the JPA delete actually deletes the entity in the datastore,but it doesn't delete the entity from the JPA Cache.. You page is actually using the JPA Cached result list to display..
The way I used to resolve the issue is to have the JPA Cache cleared every time after a delete.
Sample Code would be something like this:
EM.getTransaction().begin();
EM.remove(current_record);
EM.getTransaction().commit();
EM.getEntityManagerFactory().getCache().evictAll();
ok i think i should write it like this
*edit the problem was the findCard function, i think because of the secone instance of the EntityManager. I chnaged it without using this method to this and now it works.
public static void removeCard(Long id) {
EntityManager em = EMFService.get().createEntityManager();
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
Card card = em.find(Card.class, id);
if (card != null) {
em.remove(card);
}
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
em.close();
}
}

Resources