#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.
Related
I have a few types that have a common field(Email ID) that I am using as an #Id. These types extend from a common type User which has the Email ID field. It is something like below:
#Entity
class User{
#Id
String emailID;
}
#Entity
#Subclass(index = true)
class UserType1 extends User{
String otherField;
}
#Entity
#Subclass(index = true)
class UserType2 extends User{
String otherField;
}
Now, I want that every time I insert a subtype of User, the Email ID should remain unique across all these subtypes objects in the datastore. I tested an endpoint for the above types by inserting each of subtypes with the same EmailID and it happened successfully - Objectify shouldn't have allowed the persistence of subtypes with the same ID. As per my understanding, the ultimate uniqueness is ensured by the keys but can't I ensure uniqueness by an Id across just the subtypes especially when ID is in the base class? Is there some way to do it?
EDIT:
Although, this is not the solution I was looking for, I have handled this situation by creating a new entity type with {EmailID, Key_Subtype} which worked in ensuring the uniqueness. I just check this entity for existing emailID and I use the key for retrieving the object with another query.
If anyone comes off with a better solution, I would appreciate it.
UUID is that what you are looking for. It is generated for each entity. Type does not matter.
https://dzone.com/articles/hibernate-and-uuid-identifiers
Same Id for different entity types is definitely possible at the datastore level, see re-using an entity's ID for other entities of different kinds - sane idea?
The Id uniqueness is only guaranteed across entities of the same kind and with the same parent entity (the unique entity key is based on a combination of these 3 items). Since your subtypes are actually different entity kinds there is no problem having the same Id across these kinds, so subclassing is not the way to achieve what you want.
To have unique Ids you need to have a unique entity kind, say User. To distinguish the different user types maybe have inside User a type property which would be a reference to a entity of UserTypeX kind containing the info specific to that user type?
It sounds like you have found the "correct" solution - create an Email entity that uses the email address as the id and contains a pointer to the appropriate User entity. When creating a new User/Email, always check for pre-existence of the email address in a transaction.
This really isn't any different from using the email address as the id of the User directly except that the extra layer of indirection allows users to change their email addresses, which is generally a good idea. The transactional logic is similar either way.
Transactionally looking up & creating an entity with a natural primary key is pretty much the only way of guaranteeing uniqueness in the datastore. It is effective and scalable.
My understanding is that when using objectify, you can generate a datastore key in one of two ways:
Specify a unique ID to an object, which will be used to generate the datastore key (unique ID assigned to data member with annotation #Id)
Don't specify unique ID, so a datastore key will be autogenerated (Annotation #Id on data member still exists, but nothing is assigned to it)
Using option 1, in order to load a specified entity we first obtained a key using Key.create(SomeEntity.class, uniqueID) where uniqueID would be unique.
If I decide to go with option 2, how do I load a desired entity if I had let the datastore autogenerate a key?
With any other parameter? If you create an object without deciding on the key, but provide (for instance) a city, a userName, an email, then you search by city, username, email. Once you have that, you have the object. From there you can get the object's key if you need it.
If your entity #Id field is null and you save it synchronously with .now() then the #Id annotated field (assumed "id" in this example) will be set to an auto-allocated/generated value during the following call.
ofy().save().entity(someEntity).now();
Long myId = someEntity.getId();
Then someEntity.getId() would be a valid generated String/Long that you can use, note somewhere, provide to a user, return from an API etc so that later:
ofy().load().type(Entity.class).id(myId).now();
If you need to save the entity asynchronously (without .now()) then that's possible too, just use the allocateId function from ObjectifyFactory to set the id before saving to ensure a unique id - this is similar to your 1) but a safe way to generate the UniqueId that is assured to be unique.
Searching afterwards for the entry by querying a combination of fields should typically be avoided as depending on your data it may not match a single entry and you'd need to index those fields adding costs.
Does it make sense to create a single entity when it should only contain the #Id value as a String?
#Entity
class CountryCode {
#Id
String letterCode; //GBR, FRA, etc
}
#Entity
class Payment {
CountryCode code;
// or directly without further table: String countryCode;
}
Or would you just use the letterCode as the stringvalue instead of creating the CountryCode entity?
It should later be possible for example to fetch all payments that contain a specific countrycode. This might be possible with both solutions. But which is the better one (why)?
Yes you can if you are using the entity as a lookup. In your example, you may want to add a column for description congaing (France, Great Britain, etc.) for the letter code and a third column whether it is active or not and maybe columns for when inserted and when it was last changed.
It makes sense to create such table to provide consistency of data, that is that no Payment is created with non-existing CountryCode. Having a separate entity (that is table) together with foreign key on Payment allows checking for consistency in database.
Another possible approach is to have check constraint on the code field but this is error prone if codes are added/deleted and/or there are more than one column of this type.
Adding the letterCode the the Payment Class as String Attribute (Or Enum to prevent typo errors) will increase the fetch performance as you do not need to create a join over your CountryCode Table.
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.
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.