I upgraded my application to use Objectify4, but I can't get the ordering get working.
Here is what I did:
I have a class Offer which I want to query. This class is extended from Mail and from Model. The attribute for order should be the datetime which is indexed in the Mail-Class.
import com.googlecode.objectify.annotation.EntitySubclass;
import com.googlecode.objectify.annotation.Serialize;
#EntitySubclass(index=true)
public class Offer extends Mail {
private static final long serialVersionUID = -6210617753276086669L;
#Serialize private Article debit;
#Serialize private Article credit;
private boolean accepted;
...
}
import com.googlecode.objectify.annotation.EntitySubclass;
import com.googlecode.objectify.annotation.Index;
#EntitySubclass(index=true)
public class Mail extends Model {
private static final long serialVersionUID = 8417328804276215057L;
#Index private Long datetime;
#Index private String sender;
#Index private String receiver;
...}
import java.io.Serializable;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.Index;
#Entity
public class Model implements Serializable {
private static final long serialVersionUID = -5821221296324663253L;
#Id Long id;
#Index String name;
#Ignore transient private Model parent;
#Ignore transient private boolean changed;
...}
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;
public class DatabaseService {
static {
ObjectifyService.register(Model.class);
ObjectifyService.register(Mail.class);
ObjectifyService.register(Offer.class);
}
public static Objectify get() {
return ObjectifyService.ofy();
}
}
and that's what I want to do:
Query<Offer> result = DatabaseService.get().load().type(Offer.class).order("-datetime");
Unfortunely, the result is always NOT sorted.
Has anyone a hint?
At the low-level, this load operation has two parts:
filter by ^i = Offer
order by datetime desc
In order to make it work, you will need a multiproperty index like this:
<datastore-index kind="Model" ancestor="false">
<property name="^i" direction="asc"/>
<property name="datetime" direction="desc"/>
</datastore-index>
However, you are almost certainly abusing the datastore by making all your entities extend a polymorphic Model. You will have many problems in the future if you try to cram all of your entities into a single Kind; for one thing, practically every query will require a multiproperty index including the discriminator.
You can have a common base class, just don't make it the Kind. Keep the inheritance hierarchy, but move the #Entity up to (say) Mail. Offer can still have #EntitySubclass if you want a true polymorphic hierarchy there.
Read the objectify Concepts docs carefully and pick your Kinds carefully.
Related
I am creating a Todo app in Spring Boot and I need to create two tables: Task and Todo(Todo extends Task).
In Task table is a field called description and I would like to prevent that column to be created in Todo table.
How can I do it?
Task(parent):
package com.example.todo.model;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Task {
#Id
private long id;
private String name;
private String description;
}
Todo(child):
package com.example.todo.model;
import javax.persistence.Entity;
import javax.persistence.Transient;
#Entity
public class Todo extends Task {
private boolean isChecked;
}
I would suggest you clean up your design because concrete classes inheriting from other concrete classes is (often) a code smell. The proper solution to this is to factor out the common parts of both classes into a (abstract) super class and then add the specific fields to the concrete inheriting classes:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Completable {
#Id
private long id;
private String name;
}
#Entity
public class Task extends Completable {
private String description;
}
#Entity
public class Todo extends Completable {
private boolean isChecked;
}
so you have the behaviour grouped in the classes where it belongs and don't have to make sure that one thing contains a description while it shouldn't.
What you want cannot be done easily. But you might be trying to solve an issue in the wrong way.
From what I am reading you have a Task entity with has two separate types:
one with a checkbox indicating its completion
one with an additional description
If this is the case you might want to model the classes the same way. Thus having:
A Task entity without the description
A Todo entity extending Task with the checkbox
A new SummaryTask extending Task with a description field
I am mapping between the following models:
#Entity
#Table(name="account_type")
#NamedQuery(name="AccountType.findAll", query="SELECT a FROM AccountType a")
public class AccountType implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="account_type_id")
private Integer accountTypeId;
#Column(name="account_type_code")
private String accountTypeCode;
#OneToMany(mappedBy="accountType")
private Set<Account> accounts;
Which has a set of Account:
#Entity
#NamedQuery(name="Account.findAll", query="SELECT a FROM Account a")
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="account_id")
private Integer accountId;
#Column(name="account_number")
private String accountNumber;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="account_type_id_fk")
private AccountType accountType;
And their DTOs.
I am having problems in mapping complex types like Account:
public static Account getAccount(AccountDTO dto) {
Account model = new Account();
model.setAccountId(dto.getAccountId());
model.setAccountNumber(dto.getAccountNumber());
model.setAccountType(dto.getAccountType());
// Error: can't convert from AccountypeDTO to AccountType
return model;
}
It gives an error that it can't convert from AccountypeDTO to AccountType
so I did the following:
model.setAccountType(getAccountType(dto.getAccountType()));
Where getAccountType method is:
public static AccountType getAccountType(AccountTypeDTO dto) {
AccountType model = new AccountType();
model.setAccountTypeId(dto.getAccountTypeId());
model.setAccountTypeCode(dto.getAccountTypeCode());
model.setAccounts(dto.getAccounts());
// Now here again a similar error
}
I think it's a deep recursive? How to solve this?
My question is how to convert them efficiently.
Annex
The code of acountTypeDTO:
#Component
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class AccountTypeDTO implements Serializable {
private static final long serialVersionUID = 1L;
#NotNull
#NotEmpty
private Integer accountTypeId;
#NotNull
#NotEmpty
private String accountTypeCode;
private Set<AccountDTO> accounts;
The code of AccountDTO:
#Component
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class AccountDTO implements Serializable {
private static final long serialVersionUID = 1L;
#NotNull
#NotEmpty
private Integer accountId;
#NotNull
#NotEmpty
private String accountNumber;
private AccountTypeDTO accountType;
Two alternative approaches jump to mind but they will require some change. I will preface this by saying that I have yet to be in a situation where converting to DTOs (even if I'm doing a deep recursive conversion) is the bottleneck. Even if your performance requirements or your scale were so large that it somehow did become a bottleneck then I would personally recommend dividing the work across multiple servers before I started to worry about performance down to that level of detail. Also, it may seem inefficient but performance is rarely intuitive, have you confirmed that this conversion is a bottleneck?
The first alternative is to not use separate classes as DTOs. Some approaches use the same class as the DTO and the underlying entities and some approaches use the DTO as the parent class and the entity class as the child class. This will save you from having to do any kind of DTO<->Entity conversion. There are drawbacks, as this almost always ends up combining two responsibilities into a single class and it can make your code more complex and less readable.
The second alternative is to not return the accounts themselves but instead to convert them to IDs. In this approach your AccountTypeDTO would have a Set<Integer> accountIds instead of a Set<AccountDTO> accounts. However, this only works if your client doesn't always need to operate on every account.
import org.hibernate.annotations.OrderBy;
import javax.persistence.Column;
import javax.persistence.Entity;
public class A implements Serializable
{
#Id
#Column(name="SNR")
private long ASnr;
#OneToMany(fetch=FetchType.EAGER)
#JoinColumn(name="B")
private Set<B> bset;
public Set<B> getB() {
return this.bset;
}
#OrderBy(clause="bsnr DESC")
public void setB(Set<B> bset) {
this.bset = bset;
}
}
public class B implements Serializable
{
#Id
#Column(name="BSNR")
private long bsnr;
public long getBsnr() {
return this.bsnr;
}
public void setBsnr(long bsnr) {
this.bsnr= bsnr;
}
}
For above code #OrderBy is not working. When i try to make hibernate query then only select query is showing on console and there is no order by clause inside the sql query. Have i left something or written incorrect ?
you have used
import org.hibernate.annotations.OrderBy;
did you try with
import javax.persistence.OrderBy;
#OrderBy("bsnr")
I think you're misunderstanding what the #Orderby annotation actually does. According to the javadoc:
Specifies the ordering of the elements of a collection valued
association or element collection at the point when the association or
collection is retrieved.
The annotation does not dictate insertion order
Try adding on property or getter
I added antlr-2.7.7.jar in the classpath and used javax.persistence.OrderBy in code. Now it's working perfectly.
I want to use Postgresql network data type of mac address (macaddr) in Hibernate ORM. How could I map macaddr type to a entity class property? What is the best way of doing so? I never used non standard SQL types in Hibernate
Thx
Mac address is a String. If it's a #OneToOne relationship between the mac address and its user, then you don't have to make an entity class out of simple strings, just include it as a field on whatever entity needs it, like so:
private String macAddress;
If the same mac address is used by multiple entities and you want to reuse the value (normalize), then you'd make an entity like this:
package com.acme.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class MacAddress implements Serializable {
private static final long serialVersionUID = 1l;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String value;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
I just solve a problem like this,so I insert and get row from DB postgresql 9 successfully. The solution explained completely is in this link network postgres types on hibernate
Because of the mac-address is never totaly validated, there is no Standard-Type in Java. You can use
#ColumnTransformer(read="CAST(mac AS varchar)", write="CAST(? AS macaddr)") String
instead to read/write it as String.
I'm trying to make following JDO entity in GAE/J (I'm using Gilead).
package test.domains;
import java.io.Serializable;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import net.sf.gilead.pojo.java5.LightEntity;
import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.Key;
#PersistenceCapable(identityType=IdentityType.APPLICATION, detachable="true")
public class Banner extends LightEntity implements Serializable
{
private static final long serialVersionUID = 1058354709157710766L;
// Fields
#PrimaryKey
#Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
private Key id;
#Persistent
private String name;
#Persistent
private String sizeX;
#Persistent
private String sizeY;
#Persistent
private String description;
#Persistent
private Blob img;
// Getters and Setters
}
And encountering following problem:
[ERROR] Line 40: No source code is
available for type
com.google.appengine.api.datastore.Blob;
did you forget to inherit a required
module?
What can cause this problem? The code compiles fine without Blob object. By the way I tried to follow this example.
As far as i can tell, it is Gilead that does not have support for com.google.appengine.api.datastore.Blob.
The adapter4appengine-1.0M2.jar on contains an emulator class for 'com.google.appengine.api.datastore.Key'
Are you keeping that file in the client side? That's the only reason I can think GWT is not finding the Blob .class file.
Give it a shot.
Jaime E