VARCHAR(1) vs BOOLEAN - java

Is it a good idea to hold a VARCHAR(1) in the db with '0' for false and '1' for true? I don't think so, but it is common practice in the company I am working at the moment. Entities look like
#Entity
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "my_field")
private String myField;
// getter-setter
}
Wouldn't it be better to use BOOLEAN? I have never done this before, how does this work together with hibernate?
#Entity
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "my_field")
private boolean myField;
// getter-setter
}
Is this all that is needed?

There is a simple rule of thumb: when it surprises an experienced reader, it is bad practice.
Caveat: a well-known practice within a company might not surprise the experienced users of that company. But you still have that "surprise" problem; for example when new people get into that team/company.
The real problem with this approach: it forces your code to have knowledge that would not be required otherwise! Meaning: code defines the meaning of that database entry. When the database field has boolean type, there is no interpretation whatsoever required on top of that.

Related

Persistent Model to Domain Model mapping without exposing domains object attributes

I know this is a common question, but I haven't found another that solves my doubts.
Usually, if the project is small, I've persistence annotations in the same object that represents the domain object. This allows to load the entity from database and keep all the setters private, ensuring any instance is always in a valid state. Something like:
#Entity
class SomeEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
protected SomeEntity() {}
/* Public getters */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
/* Expose some behaviour */
public void updateAttributes(String attribute1, String attribute2) {
/* do some validations before updating */
}
}
My problem appears if I want to hava a different persistent model. Then I would have something like:
/* SomeEntity without persistent info */
class SomeEntity {
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
protected SomeEntity() {}
/* Public getters */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
/* Expose some behaviour */
public void updateAttributes(String attribute1, String attribute2) {
/* do some validations before updating */
}
}
and DAO:
#Entity
class SomeEntityDAO {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
public SomeEntityDAO() {}
/* All getters and setters */
}
My question is, how can I map SomeEntityDAO to SomeEntity without exposing SomeEntity's attributes?
If I create a constructor like: public SomeEntity(String attribute1, String attribute2, ...) {}, then anyone can create an invalid instance of SomeEntity. The same occurs if I make all setters public in SomeEntity.
I also don't think is a valid solution build the object using updateAttributes() since this will execute some validations I don't whant to execute at this point (we trust the data that's persistet in database).
I'm thinking in having all the setters protected, so the DAO can extend the Entity and have access to setters... but I'm not sure if this is a good option.
Which is the best or common approach to solve this problem?
I've had the same kind of problem. And looking around I've found no solution. Believe me, if it exists is well hidden somewhere. None that suggests what to do when you have to deal with an old project where ORM entities are everywhere and there's a big step between Domain and ORM model.
Given this, I've deducted that if you really want to keep your Domain entities pure (so non get and set - the latter I would NEVER accept!) you have to do some deals. Because there's no way to share the internals without giving the entities some extra knowledge. Beware, this doesn't mean that you have to make the Domain entities aware of the ORM layer, nor that you have to use getters. Just, what I've concluded, the Domain entities should have ways to expose them as a different model.
So, in conclusion, what I would do in your situation is to build up a Visitor pattern. The Domain entity EntityA would implement the EntityAVisitable interface to accept a EntityAVisitor or something like this.
interface EntityAVisitable {
accepts(EntityAVisitor visitor);
}
The builder implements the interface required by the Visitor, EntityAVisitor.
interface EntityAVisitor<T>{
setCombinedValue1_2(String attribute1_attribute2_combinedInEntity);
<T> build();
}
The build() function of the interface EntityAVisitor uses a generic type T. In this way the Domain entity is agnostic about the return type of the concrete implementation of the EntityAVisitor.
Is it perfect? No.
Perfect solution would be to get rid of the ORM (actually I would say that I hate them, because the way are used is most of the times wrong - but this is my personal thought).
Is it nice? No.
A nice solution is not allowed due to language restrictions (I suppose you use Java).
Does it a good work in encapsulating the real content of your Domain entity? Yes.
Not only, in this way you can decide exactly what could be exposed and how. So, in my opinion, is a good deal between keeping the entity pure and having to work with an ORM under the seat.
Domain entity should be self-validating meaning it should only validate itself based on it's internal values. If update requires validation that depends on external dependencies, then I would create an updater class that is responsible for the update. From the updater class, you can use specification pattern (as an injectable dependency) to implement the validation.
Use domain entities when modifying, and DTOs for read-only projections. There are performance and simplification gains when you use straight DTOs in read-only. This is used in CQRS patterns.
class SomeEntity {
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
public SomeEntity() {}
/* Public getters/setter */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
public Long setId() { ... }
public String setAttribute1() { ... }
public String setAttribute2() { ... }
}
//classes/interfaces named for clarity
class EntityUpdater implements IEntityUpdater {
public EntityUpdater (ISpecification spec){
}
public updateEntity(SomeEntity entity){
//assert/execute validation
}
}
Some ORMs allow setting entity values through field access (as opposed to setter methods).
JPA uses the #Access annotation. See What is the purpose of AccessType.FIELD, AccessType.PROPERTY and #Access
I created an ORM, sormula, that can use field access. See #Row fieldAccess and test case org.sormula.tests.fieldaccess.

Best practice and implementation of a builder pattern when using JPA

I have a class that is suitable for a builder pattern, there are many params and I'd rather not use a ton of telescopic constructors.
My problem is that this class is a JPA entity and that is very new to me.
Having private final data members is throwing an error as I they are not initialized in the constructor and as far as I'm aware, JPA requires an empty protected constructor.
Can anyone help please? An example would be fantastic, I've included a basic example of the code below but it's very generic. I've omitted many of the accessors and data members to save space/time.
#Entity//(name= "TABLE_NAME") //name of the entity / table name
public class Bean implements Serializable {
private static final long serialVersionUID = 1L;
#Id //primary key
#GeneratedValue
Long id;
private final DateTime date;
private final String title;
private final String intro;
//used by jpa
protected Bean(){}
private Bean(Bean Builder beanBuilder){
this.date = beanBuilder;
this.title = beanBuilder;
this.intro = beanBuilder;
}
public DateTime getDate() {
return date;
}
public String getTitle() {
return title;
}
public static class BeanBuilder Builder{
private final DateTime date;
private final String title;
//private optional
public BeanBuilder(DateTime date, String title) {
this.date = date;
this.title = title;
}
public BeanBuilder intro(String intro){
this.intro = intro;
return this;
}
public BeanBuilder solution(String solution){
this.intro = solution;
return this;
}
public Bean buildBean(){
return new Bean(this);
}
}
}
Member fields marked as final must have a value assigned during construction and this value is final (i.e. cannot change). As a consequence, all declared constructors must assign a value to all final fields.
This explain your compiler error.
From the JLS:
A blank final instance variable must be definitely assigned at the end of every constructor of the class in which it is declared, or a compile-time error occurs (§8.8, §16.9).
Not sure why you want to do that. Maybe it is better to define the member variable as
#Column(name = "id", nullable = false, updatable = false)
for example
The JPA 2.1 specification, section "2.1 The Entity Class", says:
No methods or persistent instance variables of the entity class may be
final.
..meaning that there's no way for you to build a truly immutable JPA entity. But, I don't really see how that can be such a big issue. Just don't let the entity class expose public setters?
I'm not sure what you meant for that, but having immutable objects is not a great idea when working in Hibernate (not to say you cannot do it, or you shouldn't).
Think about it, because Hibernate/JPA defines "states" for objects they are meant to be mutable; otherwise you would have a static database, or something like insert-once-and-never-modify database.
The immutable concept is a very known (nowadays) concept borrowed mainly from Functional Programming that doesn't really apply in the same way to OOP. And if you are working with Hibernate you shouldn't have immutable objects...at least till today's date.
UPDATE
If you want to have what they call read-only entities, you can use the #Immutable annotation from Hibernate itself. Pay close attention to collections as entity members.
Entities are meant to be mutable when it comes to strict Java immutability. For example, lazily loaded associations will change the object state once the association is accessed.
If you need to use entity data in a real immutable fashion (for multi-threaded purposes for example), then consider using DTOs (because entities are not meant to be accessed cuncurrently either).

Lazy proxies through interfaces (entities with final methods)

I have a requirement in my project that all my methods should be either abstract or final (please don't argue this requirement -- I know it's dumb, just assume it's there).
This is a problem with Hibernate mapped entities since Hibernate needs to create proxies in run-time in order to be able to initialize relations when those are lazily loaded. Not being able to override setter methods results in those not being loaded at all (query is indeed executed, but the object is never populated).
As stated in Hibernate's documentation:
If the final class does implement a proper interface, you could alternatively tell Hibernate to use the interface instead when generating the proxies. See Example 4.4, “Proxying an interface in hbm.xml” and Example 4.5, “Proxying an interface in annotations”.
Example:
#Entity #Proxy(proxyClass=ICat.class) public class Cat implements ICat { ... }
So theoretically it's possible to just tell hibernate to implement an interface instead of extending the original class.
I've tried this solution, but my problem comes with the relations themselves. Here's an over-simplified example:
#Entity
#Proxy(proxyClass = ICat.class)
#Table(name = "cat")
public class Cat implements ICat {
#Id
private Long catId;
#OneToMany(mappedBy = "cat", fetch = FetchType.LAZY)
private List<Kitten> kittens;
...
}
#Entity
#Proxy(proxyClass = IKitten.class)
#Table(name="kitten")
public class Cat implements IKitten {
#Id
private Long kittenId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="catId")
private Cat cat;
...
}
Now if I try to obtain a Cat object, I get a ClassCastException since it is trying to cast an IKitten collection into a Kitten collection. Which leads me to think I should declare relations using interfaces instead of implementations -- which also produces a compilation-time error since my Interfaces are never declared as entities, but the implementations are (which is clearly stated in the example from the documentation).
How can I solve this?
You con use the interface in both one-to-many and many-to-one associations, but you need to supply the actual Class in the targetEntity attribute. The relations should be something like this:
#Entity
#Proxy(proxyClass = ICat.class)
#Table(name = "cat")
public class Cat implements ICat {
#Id
private Long catId;
#OneToMany(mappedBy = "cat", fetch = FetchType.LAZY, targetEntity=Cat.class)
private List<IKitten> kittens;
...
}
#Entity
#Proxy(proxyClass = IKitten.class)
#Table(name="kitten")
public class Cat implements IKitten {
#Id
private Long kittenId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="catId", targetEntity=Cat.class)
private ICat cat;
...
}
I had the same requirement before, and bypassed it by declaring final all classes. My hibernate structure was not proxying, and thus I don't know if that will fix the problem, but the requirement. There is a side problem if you are using mockito. Have this in mind.
By the way, there is a typo in the second class shown in your code, it shall be named Kitten

how to model a singleton object to table through hibernate?

I have a global config object in my project and there can ever be 0 or 1 instance of this class that i want to persist in db. What is the best way to do this ? One trick i know here is to have a "constant" field mapped with unique constraint set on it, are there other such ways as this looks a little hacky ?
Here's what i tried :-
#Entity
public class DTLdapConfig implements Serializable {
#GeneratedValue(strategy=GenerationType.TABLE)
#Id
private int id;
#Column(unique=true)
private boolean singletonGuard;
// no public setter getter for singletonGuard
// other code below
}

JPA 2.0 insufficient privileges when performing insert from transaction

After much searching and trials, I am stuck... I have two classes, one is ExpectedSecurityReturn and the other is ForecastReturnType. ForecastReturnType is a member of ExpectedSecurityReturn but should not be inserted when persisting data. I keep getting an "insufficient privileges" but I know that the user does have the delete/insert privileges to the table expected_security_return since I tested with JDBC and JPA delete works fine. Therefore, I think that it has to do with my classes.
#Table(name = "EXPECTED_SECURITY_RETURNS")
#Entity
#IdClass(ExpectedSecurityReturn.ExpectedSecurityReturnPK.class)
public class ExpectedSecurityReturn {
#Id
#Column(name = "REP_SEC_ID")
private Integer repSecId;
#Id
#Column(name = "AS_OF_DATE")
private Date date;
#Id
#ManyToOne(optional = false)
#JoinColumn(name = "RETURN_TYPE_ID", referencedColumnName = "RETURN_TYPE_ID", insertable=false)
private ForecastReturnType returnType;
#Column(name="CURR_TOUSD_RET") // local currency to usd
private Double currencyToUsdReturn;
}
The primary key class, which includes ForecastReturnType:
// ------------------------------
// PK
// ------------------------------
public static class ExpectedSecurityReturnPK implements Serializable {
private static final long serialVersionUID = 1325372032981567439L;
public ExpectedSecurityReturnPK() {
}
public ExpectedSecurityReturnPK(final Integer repSecId,
final Date asOfDate, ForecastReturnType returnType) {
if (repSecId == null)
throw new IllegalArgumentException("null rep sec id");
if (asOfDate == null)
throw new IllegalArgumentException("null asOfDate");
if (returnType == null)
throw new IllegalArgumentException("null returnType");
this.repSecId = repSecId;
this.date = new Date(asOfDate.getTime());
}
#Override
public boolean equals(final Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
final ExpectedSecurityReturnPK that = (ExpectedSecurityReturnPK) o;
if (repSecId != that.repSecId)
return false;
if (!date.equals(that.date))
return false;
if (!returnType.equals(that.returnType))
return false;
return true;
}
#Override
public int hashCode() {
int result = repSecId;
result = 31 * result + date.hashCode();
result = 31 * result + returnType.getForecastTypeId();
return result;
}
private int repSecId;
private Date date;
private ForecastReturnType returnType;
}
and ForecastReturnType:
#Table(name="EXPECTED_SEC_RET_TYPE_DECODE")
#Entity
public class ForecastReturnType {
#Id
#Column(name="RETURN_TYPE_ID")
private int forecastTypeId;
#Column(name="SHORT_NAME")
private String shortName;
#Column(name="LONG_NAME")
private String longName;
#OneToMany(fetch=FetchType.LAZY, mappedBy="returnType")
Collection<ExpectedSecurityReturn> expectedSecurityReturns;
}
Could anyone help me figure out what I am doing wrong? I tried many things without success... I think that the culprit is ExpectedSecurityReturn.returnType since I know that the user does not have privileges.
Basically, I need to insert/persist ExpectedSecurityReturn instances.
Well, there's a couple of things.
I would heavily not recommend even trying to do this. You can waste away your life figuring out JPA annotations and weird issues like this that never quite seem to work right. You'll also find that different JPA providers will behave slightly differently when it comes to more complex structures like this, and it goes doubly for inheritance.
You're really much better off creating a unique key on EXPECTED_SECURITY_RETURNS, and just living with it, it will make your Java life much much easier.
If you have to do something like this, I'm not surprised that JPA is balking at having a primary key component be another entity object. Whilst this in of course quite possible in the RDBMS, it's seemingly little things like this that will trip up JPA.
I would also check the query logs that your JPA impl will put out (it's configurable fairly easily in the persistence definition for most JPA providers, certainly Ecpliselink and Hibernate). I'd be willing to bet it's trying to run an update on EXPECTED_SEC_RET_TYPE_DECODE, and if not, it might be trying to obtain a lock (table, row or other depending on your DBMS). If the user doesn't have permission to either execute a lock or an update on that table, depending on the exact implementation, the query could fail with a permissions problem.
It is reasonable for JPA to want to hold a lock on that table because there is a chance that during the transaction, the entry that is being referenced in EXPECTED_SEC_RET_TYPE_DECODE may get changed, so it must ensure that it doesn't whilst updating/inserting on the other table. Last I checked, there is no way to tell JPA that this table is essentially static. If you're using Hibernate, you might try the #ReadOnly annotation, but in the past, not much I've tried can get around things like this.
If you do find a better solution, feel free to post it so that the rest of us can learn!!
I agree with PlexQ that derived identities and composite keys are pretty complicated parts of JPA.
However, JPA 2.0 specification contains a good set of examples to illustrate these topics, and these examples mostly work across different JPA implementations.
For your case specification suggests you to put into #IdClass a field with name of #ManyToOne field and type of #Id field of referenced entity:
#Entity
public class Employee {
#Id long empId;
String empName;
...
}
public class DependentId {
String name; // matches name of #Id attribute
long emp; // matches name of #Id attribute and type of Employee PK
}
#Entity
#IdClass(DependentId.class)
public class Dependent {
#Id String name;
// id attribute mapped by join column default
#Id #ManyToOne Employee emp;
...
}
See also:
JSR 317: JavaTM Persistence 2.0
After a lot of trial and error, I finally figured out that the error was legitimate and I did not indeed have sufficient (ie insert) privileges, only delete!!

Categories

Resources