I am try to find out how to enforce uniqueness in fields other than the unique id.
Example:
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class User implements IsSerializable {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
#Persistent
private String name;
#Persistent
private String email; // <= I want this to be unique as well
}
In the example above, how can I enforce uniqueness of the email value across the database?
Daniel
There is currently no built in way using the app engine datastore. See this datanculeus ticket for example. (Note that JDO itself does have a #unique annotation.)
One way to 'fake' it would be to create another kind/class called Email with the email itself as a key, and the User's key as a property. Since the email is now a key, it will be forced to be unique. Just make sure your Email entities are top level entities, not children of their associated User. You'll also have to pay close attention to your use of transactions to make sure you don't let a duplicate slip through the cracks if two users try to use the same email at the same exact time.
I have written a class that takes care of all the functionality for adding Unique Fields to the App Engine Entities. Please feel free to use it.
Plug this class in your project and simply add get and update methods and provide the Entity Name, Field Name and the unique field value
Source code is available here:
http://code.google.com/p/appengine-uniquefields/
This feature is not supported yet. If you decided to write a DAO Layer in your project (Not a bad idea), you can do a query that will test whatever limits you want inside of MyObjectDAO.addMyObject(o) which will throw a MySuperDuplicateValueException.
Related
I am making a small restful service for user management. By assignment, the User is defined by the following values:
◦ First name
◦ Last name
◦ Date of birth
◦ Login
◦ Password
◦ Input field “About me”
◦ Address of residence (country, city, street, house, flat)
When designing, I paid attention to the address and thought that it would be wrong to write everything together in one address field and make a similar attribute in the database table, because then different filtering by addresses would become very inconvenient. Then I delimited the address field into 5 fields (those in brackets). However, having done so, I realized that my class, given the id field, has 13 fields, what, in my understanding, makes the class too overloaded and "wrong". Then I decided to make a separate class for the address and use it as a field for the user, namely:
#Entity
public class UserAddress {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
private String country;
private String city;
private String street;
private int house;
private int flat;
}
And having done so, I'm not entirely sure how to proceed, as a result of which I have the following questions:
Should I move 5 address fields into a separate class in UserAddres?
If so, is it worth to make this class Entity and creating table in the database for it?
Should I consider it like a complete class (create getters / setters, equals and hashcode, service layer, controller and repository layers)?
Will filtering users by address become even more complicated than it was originally?
What is the best way to deal with such a situation?
Moving them into an extra table allows you to store more than 1 Address per user without redundancy of user data (like name).
Yes, because JPA / Hibernate will take care of PK/FK-Relationship using #OneToMany and #ManyToOne annotations.
Equals/Hashcode yes. Getters and Setters probably yes, depends on the way you handle this data. If you've got user input, e.g. via a GUI, you will need getters and setters. Somewhere you probably have to "fuse" address and user data to your Service's User data (the one going out).
Edit: If an Address object is invalid without belonging to a User, then only being able to manipulate the Address-Object via its User-object can help your data consistency.
No. JPA offers convenient ways to join tables.
The best-practice regarding your Restful Service would be to have a mapper between your Entities (User + Address between DB and App) and your DTOs (User + Address, between App and 3rd Party).
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private String externalID; //<--- why we need this?
}
Someone has suggested me to include an external Id field in a class something like that? Any suggestions why that could be?
Not sure, what exactly meant by externalID here, since the case of usage is not clear.
But, I assume a couple of cases:
1. External service
External id may be used to map your entity with some id of another resource from different services. Something, that identifies this entity in another system.
For example: in externalID may be stored person twitter id or bank account id.
2. Security-wise
externalID is used to protect (encapsulate) internal id been visible outside, which may cause some security vulnerabilities.
For example:
In your case, internal id is Integer with GenerationType.AUTO, that means, all entities will have an incremental id: 1, 2, 3, ...
Knowing that someone may analyze your API calls and easily iterate through all your accounts via API, e.g: GET api/person/{id}.
Usually, a different type of IDs is used to solve this problem, like UUID, e.g.: 8b9af550-a4c7-4181-b6ba-1a1899109783. Which can be used as externalID in your case.
So, I assume this is the reason to add additional externalID to your entity.
Note: if your Database supports the usage of UUID (or store it as String), you can simply replace your internal id type with UUID and get rid of externalID here.
It is possible that externalID represents the Primary Key of another table that person is relative to. String is quite arbitrary though, you would generally use an Integer, Long, or UUID to represent a primary key. Might need more context in the question.
The purpose behind an external ID is to link your entity with another representation of it from a system that is decoupled from yours.
For example, if you want the store the Facebook ID for SSO reasons, you would do it through a field that could be called externalId, or something like that. Another example might be that you imported some accounts from another database, and you want to store the Primary Key from the source entity that has been imported.
Otherwise, if that field does not represent anything in your business logic, get rid of it.
Hypothetical code:
#Entity
public class MyEvent {
#Id Long id;
#Index String name;
Ref<Location> myLocation;
}
#Entity
public class Location {
#Id Long id;
#Index String city;
#Index String country;
}
Is there a way for me to do a filter to find all events within a particular city? This seems like it would need a join, which isn't supported, but I wanted to double check since I can't find a definitive answer.
Also, what is the correct way of structuring the data if this type of filtering isn't possible? Would I need to have a denormalized MyEvent entity with all the fields that I could possibly filter on?
As you can read in the Objectify documentation, Ref properties are more of an Objectify sugar than a Datastore feature. They're stored as Key properties in the Datastore, and so it's not possible to query against the properties of the entity which the key might point to.
If you want to query for events within a city, you could either store the event's city on the event itself and query against that, or query all locations within a city and then query for any events matching those locations (that is, by querying against the location keys, which are stored on the events). A third option would be to make cities into actual entities with a collection-type field of Events. You could also make use of ancestor queries - see the "Datastore Queries" docs for more information.
I have the following Student class.
public class Student implements Serializable {
private int contestantId;
private String email;
private String password;
private String firstName;
private String lastName;
private String contact;
private String country;
private String countryCode;
private String school;
...
A couple more properties as well as getters and setters...
...
}
My business logic requires that the email and contact number be unique. In the case of a traditional RDMS, I can easily accomplish this by setting the column to UNIQUE and handling any Constraint Exceptions that arises.
Due to our hosting environment (OpenShift doesn't scale the database), I would like to convert my existing application from storing data directly in PostgreSQL to using Infinispan's distributed data grid. However, the main issue I have now is that I cannot figure out how to enforce the UNIQUE constraints for both the email and contact.
Is there a workaround for my problem or do I have to conclude that Infinispan isn't suited for my particular set of requirements?
A datagrid can deliver impressive scalability features because every entry is strictly independent. So it doesn't even make sense to think about a "unique" validation, but there are options by reformulating the problem.
You could use a Cache in which you store your Student data keyed by email, and a second Cache using a key by contact number. Before creating a new entry, you verify it's not existing already. Optionally you could wrap both operations in a transaction, or use putIfAbsent operations. In one cache you store the data, in the second cache you could store a copy (if that's useful) or just a marker token, or the key for the other Cache to easily find Students from different properties.
You could use indexing, so you can search for Students by email / contacts / etc..
You could use a combination. I would likely use indexing to check before attempting to insert, so I have flexibility on accessing any fields, and don't need to duplicate data or make too unusual mappings, but then at insertion time I would still use a transaction with a putIfAbsent operation to make sure a concurrent thread won't attempt to create the same student at the same time.
I am new to both stackoverflow and JPA so I will try to explain this the best i can.
In an entity I want to set the foreign key by giving the int value but also I want to set it by giving an object. Here is some code to explain it better.
#Entity
public class Thread implements Serializable {
#ManyToOne
#JoinColumn(name = "accountId", referencedColumnName = "id", nullable = false)
public Account getAccount() {
return account;
}
#Column(name = "accountId")
#Basic
public int getAccountId() {
return accountId;
}
}
I have tried several ways but the code above is the best example for what I am trying to achieve. I understand that setting insert = false and update = false, in either of the 2 methods, makes this code work as far as compiling and running. But I want to be able to insert the accountId by using an Account object AND by setting the actual int accountId.
The reason for this is because sometimes, in my server, I only have the accountId and sometimes I have the Account object.
I also understand that the best solution is probably to use account.getId() when creating the Thread and setting the accountId. But it would be logically nice in my server to be able to just use the object.
Thanks in advance!
I think you have hit a conceptual problem in your application. You should stick to set the entity and do not use any foreign key values when using JPA. The cause of the problem is that your application is only providing the accountId at some point.
This may be due to different reasons. If this is because the part of the application only providing the accountId is legacy, than I would think it is perfectly fine to have an adapter that converts the accountId into an Account entity and then set that entity. Also not that the adapter could create a JPA proxy so that no actual database access is required at that point. Another reason I can think of, is that the application is loosing information at some point during processing. This may be the case when the application is using the Account in some place and only hands over it's Id to the code in question. Then such code should be refactored to hand over the entity.
In your specific case you are also able to use both, account as entity and the foreign key as attribute with both being insertable and updatable. You just have to make sure, that the accountId attribute value is consistent with the foreign key pointing to the row represented by the account entity. JPA providers should be able to handle this (I know OpenJPA does for example). However you are a bit restricted with this. For example you are only able to read the accountId attribute value, because setting it to a different value would cause an inconsistency between the account entity value.