I am trying to add a filter to check for duplicate values that a user might input. I am not sure where I am going going wrong in my query.
My query doesnot enter the loop to check if the name already exists.
I am fairly new to google-could. If someone can tell me on how I can fix my problem or if there is a better solution.
else if ( commandEls[0].equals( "add_director" ) ) {
String name = commandEls[1];
String gender = commandEls[2];
String date_of_birth = commandEls[3];
boolean duplicate = false;
//add a director record with the given fields to the datastore, don't forget to check for duplicates
Entity addDirectorEntity = new Entity("Director");
// check if the entity already exits
// if !duplicate add, else "Already exisits"
Query directorExists = new Query("Movies");
// Director Name is the primary key
directorExists.addFilter("directorName",Query.FilterOperator.EQUAL, name);
System.out.print(name);
PreparedQuery preparedDirectorQuery = datastore.prepare(directorExists);
System.out.print("outside");
for(Entity directorResult : preparedDirectorQuery.asIterable()){
// result already exists in the database
String dName = (String) directorResult.getProperty(name);
System.out.print(dName);
System.out.print("finish");
duplicate = true;
}
if(!duplicate){
addDirectorEntity.setProperty("directorName",name);
addDirectorEntity.setProperty("directorGender",gender);
addDirectorEntity.setProperty("directorDOB",date_of_birth);
try{
datastore.put(addDirectorEntity);
results = "Command executed successfully!";
}
catch(Exception e){
results = "Error";
}
}
else {
results = "Director already exists!";
}
}
Non-ancestor queries (like the one in your example) are eventually consistent, so they cannot reliably detect duplicate property values. Ancestor queries are fully consistent, but they require structuring your data using entity groups, and that comes at the cost of write throughput.
If the directorName property in your example is truly unique, you could use it as the name in the key of your Director entities. Then, when you are inserting a new Director entity, you can first check if it already exists (inside of a transaction).
There's no general, built-in way in Datastore to ensure the uniqueness of a property value. This related feature request contains discussion of some possible strategies for approximating a uniqueness constraint.
I'd also recommend reading up on queries and consistency in the Datastore.
That is a valid thing to do but i figured out my problem.
I am making an Entity for Director where as That should be for movies.
Related
I am using spring boot repository with native query. While I am trying to update few fields by query and supply wrong values it is not throwing any exception.
here is my code,
#Modifying(clearAutomatically = true)
#Query(value = "update tbl_user set is_phone_Verified=true, mobile_verification_otp='XXX', updated_At=:updatedAt where " +
"phone_number=:registeredMobile and " +
"mobile_verification_otp=:phoneVerificationOtp", nativeQuery = true)
void updateMobileVerified(#Param("registeredMobile") String registeredMobile,
#Param("phoneVerificationOtp") String phoneVerificationOtp,
#Param("updatedAt") Date updatedAt);
Now, the issue is if I supply even wrong otp value, it is not throwing any exception. From service I am calling this method. and if there is no exception then I am returning true. Please find the service method.
#Override
public Boolean mobileVerification(String registeredMobile, String phoneVerificationOtp) {
try{
Date date = new Date();
userRepository.updateMobileVerified(registeredMobile,phoneVerificationOtp, date);
return true;
} catch(Exception e) {
return false;
}
}
Can someone please suggest me some way how can I determine if the update is successful.
Thanks.
If you would like to determine whether any rows were updated, the updateMobileVerified method can be defined to return int instead of void to indicate the number of rows updated
It seems that you are updating an unknown entity in the database. I highly recommend looking for a tbl_user entity by a unique id, like user_id or something like that. If the user doesn't exist, you either throw an exception or return false. In the case the given tbl_user was found, you basically update your desired attributes. This way, you force a strong control over updating users' data. I hope this might clarify your vision.
I have an object with 70 attributes. For ease of use I created 2 objects, a 'main' object and a 'details' object, with 1:1 relationship based on an auto-generated integer ID. I had a SEARCH screen that allowed searching on any of the main attributes, for which I build Restriction objects for whatever the user typed in. What was nice was that I did this all through iterating through the fields and building criterion - I didn't need ugly code to specifically handle each of the 30 attributes.
Now they want to search on the details fields as well. My previous screen-field-iterating code works perfectly with no changes (the whole reason for making it 'generic'), however I cannot get the JOIN to work to query on details fields.
class House {
Integer houseID;
String address;
. . .
HouseDetails houseDetails;
}
class HouseDetails {
Integer houseID;
String color;
. . .
}
I tried to create an alias and add it to the criteria :
criteria.createAlias("houseDetails", "houseDetails");
but I get this error :
org.hibernate.QueryException: could not resolve property: color of: House
Here's the thing - I know this would work if I prefix my restrictions with the alias name, but I do NOT want to have to know which table (House or HouseDetails) the field comes from. That would ruin all the automatic looping code and create specific code for each field.
Since SQL can do this as long as the column names are unique :
select * from house, housedetails where house.houseID = housedetails.houseID
and color = 'blue';
I'm wondering how can I get this to work using criteria??
As an aside, but related to this : Is there a way to perform something like Java's introspection on Hibernate HBM.XML mapping files? A number of times I've wanted to do this to solve problems but never found an answer. For the above problem, if I could easily find out which table contained each field, I could add the prefix to the Restriction. Something like this :
// Map of search keys (columns) to searching values
for ( String key : parms.keySet() ) {
String val = parms.get(key);
if ( HIBERNATE-SAYS-KEY-IS-FROM-DETAILS-TABLE ) {
key = "houseDetails." + key;
}
criteria.add(Restrictions.eq(key,val));
}
You can make method to find table name for passed column name.
By using SessionFactory.getClassMetaData() you can get all the information about that class. Once you have ClassMetaData then you can get all the property names. An demo method is shown below:
public String findTableName(String columnName)
{
boolean found=false;
Map<String, ClassMetadata> classMetaData = sessionFactory.getAllClassMetadata();
for (Entry<String, ClassMetadata> metaData : classMetaData.entrySet())
{
String[] propertyNames = metaData.getValue().getPropertyNames();
for (String property : propertyNames)
{
if(property == columnName)
{
return metaData.getKey() + "." + property;
found=true;
break;
}
}
if(found)
break;
}
}
The alias mechanism in hibernate and the Criteria API is pretty well specified. I suggest going through the documentation a little a bit.
I think what you want is something like this:
Criteria criteria = session.createCriteria(House.class);
criteria.createAlias("houseDetails.color", "houseColor");
criteria.add(Restrictions.eq("houseColor", "red"));
the question i am going to ask is very old and i think it asked on SO 5-10 times.
but mine has a different situation.
Read my Problem before making it duplicate by so many wise (over) SO users.
I am importing CSV sheet containing 10K records in my application.
My logic works in following manner,
(1) Validate & Import Sheet
(2) Save to the database if record does not exist
Step 2 is done for each and every record of the sheet.
in the step -2 i have to generate UUID to identify a particular record later ,
in my first solution
// this might be unique in some cases
String id = UUID.randomUUID().toString();
but i checked that it does generate unique id in each case , for example
if i import 10 sheet one by one with different records in it, all 10 times i am getting
duplicate key error from database for at least 4000 times in each import and save operation,
that means that out of 10,000 key generation it generates only 6000 unique ids.
so then i generate an alphanumeric code which length is 6 , some thing like
eSv3h7
and append it to previously generated id and hence get the following id
d545f2b2-63ab-4703-89b0-f2f8eca02154-eSv3h7
after testing still there is a problem of id duplication.
I also tried several combination mentioned here and on other sites but still there is a same problem of id duplication,
Now i am wondering that this occurs only for 10k records saving in loop , actually i need to import sheet which is having 8 million records in it
so how can i solve my problem of generating a Unique id in my particular case ?
Update 1 - based on all the comments
Try this thing at you end.
loop through 1 to 10,000
generate uuid in the loop
store it somewhere in simple text file
then make a simple program to find the duplicates from them , if you do not find any one duplicate in first attempt , repeat all above steps again and again and i am sure you will find duplicates.
in the past i am also strong believer of the same thing that UUID will never generates duplicates, share me your result of above test.
Update 2 - Code
This is the method which is called by each record of the sheet to be saved by caller method' loop.
#Override
public void preSynchronizedServiceExecution(ServiceData sData,
ValueObject valueObject) throws BlfException {
PropertyVO pVO = (PropertyVO) valueObject;
ArrayList<CountyAuctionPropertyVO> capList = pVO
.getCountyAuctionPropertyList();
for (CountyAuctionPropertyVO caVO : capList) {
TadFrameworkUtil.processValueObjectKeyProperty(caVO, true);
TadFrameworkUtil.processValueObjectKeyProperty(caVO
.getPropertyLastOwner(), true);
TadFrameworkUtil.processValueObjectKeyProperty(caVO
.getPropertyLastOwner().getAdd(), true);
}
ArrayList<PropertyAminitiesVO> amList = pVO.getPropertyAminitiesList();
for (PropertyAminitiesVO pamVO : amList) {
TadFrameworkUtil.processValueObjectKeyProperty(pamVO, true);
}
ArrayList<PropertyAttributesVO> atList = pVO
.getPropertyAttributesList();
for (PropertyAttributesVO patVO : atList) {
TadFrameworkUtil.processValueObjectKeyProperty(patVO, true);
}
TadFrameworkUtil.processValueObjectKeyProperty(pVO, true);
TadFrameworkUtil.processValueObjectKeyProperty(pVO.getSiteAdd(), true);
}
Following is id generation method
public static String generateUUID() throws BlfException {
// this might be unique in some cases
String id = UUID.randomUUID().toString();
// introduce custom random string in mixing of upper and lower
// alphabets,
// which is 6 character long
// and append it to generated GUID.
String rs = randomString(6);
id = id.concat("-").concat(rs);
return id;
}
Update 3 (Method added)
public static void processValueObjectKeyProperty(ValueObject valueObject,
boolean create) throws BlfException {
String key = (String) BlfConverter.getKey(valueObject);
if (!StringUtility.isStringNonEmpty(key)) {
throw new BlfException(valueObject.getObjectName()
+ "- key property does not exist.");
}
if (create) {
String id = generateUUID();
valueObject.setProperty(key, id);
} else {
String exisitingId = valueObject.getProperty(key);
if (!StringUtility.isStringNonEmpty(exisitingId)) {
String id = generateUUID();
valueObject.setProperty(key, id);
}
}
}
The random string method is just a simple methods of 2 lines which generates alpha numeric random string of length 6.
please ask me if you need anything more so i can post here.
Update 4 (Sample genearted UUID )
d545f2b2-63ab-4703-89b0-f2f8eca02154-eSv3h7
6f06fa28-6f36-4ed4-926b-9fef86d002b3-DZ2LaE
20142d05-f456-4d72-b845-b6819443b480-xzypQr
67b2a353-e7b4-4245-90a0-e9fca8644713-AgSQZm
8213b275-2cb1-4d37-aff0-316a47e5b780-vMIwv9
and i am getting accurate result from database if i need to fetch it from there.
Thanks
Thanks for all your user who seriously study my question and spent some time to help me in solving it.
I found that the error was in Database layer of business logic foundation.
One of the Object needs to Updated but it was created using previous
existing id so that i was getting the Duplicate Primary key Error.
I develop a Unit Test for id generation and tested UUID for more than
one billion key , it is guaranteed to be unique, it is true in all
circumstances.
Thanks again to everyone.
I have this code thtat works just fine w/o HR:
protected Entity createEntity(Key key, Map<String, Object> props){
Entity result = null;
try {
Entity e = new Entity(key);
Iterator it = props.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
String propName = entry.getKey();
Object propValue = entry.getValue();
setProperty(e, propName, propValue);
}
key = _ds.put(e);
if (key != null)
result = _ds.get(key);
} catch (EntityNotFoundException e1) {
}
return result;
}
This is just a simple method where its function is to create a new Entity out a a given key, just return NULL otherwise. This works fine without the HR configuration in JUnit however when I configured it, I am always getting an error, where _ds.get(key) can't find the key throwing:
EntityNotFoundException: No entity was found matching the key:
Specifically when doing:
while(it.hasNext()){
// stuff
createEntity(key, map);
// stuff
}
I assume that the problem in my code is that it tries to fetch the entity too soon. If thats is the case, how can I deal with this wihout resorting to Memcache or anything like that.
Update:
When the createEntity is executed within a transaction, it fails. However if I remove it outside of the transaction if fails miserably. I need to be able to run within a transaction, since my higher level API put lots of objects that needs to be there as a group.
Update:
I followed Strom's advise however I found a weird side effect, not doing a _ds.get(key) on the method, makes my PreparedQuery countEntities to fail. Where if add a _ds.get(key) even I don't do anything or save the Entity return from that get countEntities return the expected count. Why is that?
You try to create a new entity and then read back that entity within the same transaction? Can't be done.
Queries and gets inside transactions see a single, consistent snapshot of the datastore that lasts for the duration of the transaction. 1
In a transaction, all reads reflect the current, consistent state of the Datastore at the time the transaction started. This does not include previous puts and deletes inside the transaction. Queries and gets inside a transaction are guaranteed to see a single, consistent snapshot of the Datastore as of the beginning of the transaction. 2
This consistent snapshot view also extends to reads after writes inside transactions. Unlike with most databases, queries and gets inside a Datastore transaction do not see the results of previous writes inside that transaction. Specifically, if an entity is modified or deleted within a transaction, a query or get returns the original version of the entity as of the beginning of the transaction, or nothing if the entity did not exist then. 2
PS. Your assumption is worng, it's impossible to fetch an entity by key "too soon". Fetches by key are strongly consistent.
Also, why do you need to retrieve the entity again anyway? You just put it in the datastore yourself, so you already have its contents.
So change this part:
key = _ds.put(e);
if (key != null)
result = _ds.get(key);
To this:
key = _ds.put(e);
if (key != null)
result = e; // key.equals(e.getKey()) == true
Welcome in GAE environment, try to read it more times before you give up :
int counter = 0;
while (counter < NUMBER_OF_TRIES){
try {
//calling storage or any other non-reliable thing
if(success) {break;} //escape away if success
} catch(EntityNotFoundException e){
//log exception
counter++;
}
}
Important note from google documentation : "the rate at which you can write to the same entity group is limited to 1 write to the entity group per second."
source : https://developers.google.com/appengine/docs/java/gettingstarted/usingdatastore
I'm struggling with a homework assignment and am getting hung up on some SQL queries.
My query is interrogating an inventory database for the quantity of some item. The query requests the column with the name quantity_in_stock from the table, given the primary key.
I have initialized some prepared statements. This is the one I'm using here:
stmtFindColumn = Database.getConnection().prepareStatement(String.format("select ? from %s where %s = ?",
INVENTORY_TABLE_NAME, SKU) );
Now a separate method is called. I pass it a static const QTY_IN_STOCK, which is defined as "quantity_in_stock" and the item's SKU number, which is the primary key in the table.
private int getIntegerFromTable(String column, String key) {
int toReturn = 0;
try {
// Complete the prepared statement
stmtFindColumn.setString(1, column);
stmtFindColumn.setString(2, key);
ResultSet result = stmtFindColumn.executeQuery();
toReturn = result.getInt(column);
} catch (SQLException e) {
LOG.error(e.getMessage());
e.printStackTrace();
}
return toReturn;
}
When I run the query I get an sql exception that tells me: Invalid column name quantity_in_stock.
I have tried using a while loop processing result.next() and get the same error. I can't find any examples of how to properly get the results when you know only a single record is being returned.
Help!
EDIT: OK, I've found that part of my problem is I'm not getting a result set, where I should expect one. Any ideas?
UPDATE: I've tested my code, using a garden variety statement and a plain string query instead and it works just fine. So the problem is in my use of the prepared statement. Can someone check if I'm using the ? wildcards correctly? Thanks!
as far as i know, the column name may not be a parameter ...
DarkSquirrel42 is right -- you can't replace the column list of the select using a ? parameter marker. Instead, you can String.format that into place too, for example.
bad:
*select ? from INVENTORY_TABLE_NAME where SKU = ?
good:
select QUANTITY_IN_STOCK from INVENTORY_TABLE_NAME where SKU = ?