Eigener Primary Key (ID) Generator für EJB3

ThirdKeeper

Mitglied
Hallo zusammen,

(!) Ziel:
Erzeugung einer eigens generierten Id, die 2-stellig für Jahr + 5-stellig für laufende Nr. aufgebaut sein soll.

:eek: Beispiel:
Eine EJB namens Rechnung wird z.B. Als erstes Rechnungsdokument des aktuellen Jahunderts am 01.01.2008
in der DB erstellt. Jetzt soll der Primary key so aussehen: "0800001" so dass man z.B. später auf einer Rechnung
die Daten wie folgt ausgeben kann: "RG 08 - 00001".
Die 5te Rechnung am 02.01.09 sollte den key 0900005 für die DB erzeugen.

:confused: Allgemeine Problematik:
Wie bekommt man es hin, dass EJB's einen Schlüsselgenerator verwenden der:
a) eine vorangestellte beliebige Zahlenkombination mit einem angehangenen autowert verwendet und
b) den Autowert zu beginn eines neuen Jahres wieder auf 0 oder einen anderen beliebigen Wert setzt?

Verwendete Tools & Frameworks:
JBoss 4, Eclipse 3.3.0, JPA (EJB3 - JEE5), MySQL 5

:rolleyes: Ansatz:
Code:
public class DocumentIdGenerator
implements Serializable{
	private static long currentId=0;

	private long id = 0;
	public DocumentIdGenerator (){
		this.id = getNextID();
	}

	public long getId(){
		return id;
	}
	public void setId(long id){
		this.id = id;
	}

	public static long getCurrentId(){
		return currentId;
	}
	public static void setCurrentId(long id){
		currentId = id;
	}

	public synchronized long getNextID(){
		currentId++;
		if(currentId < (cutYear(getActialYear())*100000))
			currentId = cutYear(getActialYear())*100000 + 1;
		return currentId;
	}

	public static short getActialYear() {
		return (short)cutYear(Calendar.getInstance(Locale.GERMANY).get(Calendar.YEAR));
	}
	public static short cutYear(int year){
		return (short)(year-=((year/100)*100));
	}
}
 
Zuletzt bearbeitet:
da musst du einfach einen Custom Sequence generator für Hibernate implementieren:
http://www.hibernate.org/296.html

Einfach? ^^
Da bekomm ich ja bei der Betrachtung des Quellcodes schon Magengeschwüre. :confused:

Man kann mittels JPA (EJB3) doch sicherlich einfacher einen SequenceGenerator per Annotation hinzufügen.
Beispiel:
Code:
@Id
@GeneratedValue(generator = "docIdGenerator")
Oder lieg ich da falsch?

Ausserdem benutze ich kein Hibernate für das Persistence-Mapping.
 
Zuletzt bearbeitet:
Nach langen suchen per :google: und in diversen Büchern und Zeitschriften
habe ich immer noch keine Lösung gefunden. (!)

Hat niemand eine Idee wie das Problem (ohne Hibernate) zu lösen ist? :confused:
 
Der einzige Ansatz der mir logisch erscheint, aber leider nicht funktioniert! :mad:

Anlegen einer IdClass:
Code:
@IdClass(DocumentIdGenerator.class)
public class DocumentIdGenerator
implements Serializable{
	private static final long serialVersionUID = -4338849341607873156L;
	private static long currentId=0;

	@Id
	private long id = 0;
	protected DocumentIdGenerator (){
		this.id = getNextID();
	}

	public long getId(){
		return id;
	}
	public void setId(long id){
		this.id = id;
	}

	public static long getCurrentId(){
		return currentId;
	}
	public static void setCurrentId(long id){
		currentId = id;
	}

	@Transient
	public synchronized long getNextID(){
		currentId++;
		if(currentId < (cutYear(getActialYear())*100000))
			currentId = cutYear(getActialYear())*100000 + 1;
		return currentId;
	}

	public static short getActialYear() {
		return (short)cutYear(Calendar.getInstance(Locale.GERMANY).get(Calendar.YEAR));
	}
	public static short cutYear(int year){
		return (short)(year-=((year/100)*100));
	}
}

Verwendung der IdClass in der EntityBean:
Code:
@Entity(name = "TestDocument")
@Table(name = "doc_TestDocument")
@PersistenceUnit(name="TestDocument")
public class TestDocument implements Serializable{
	private static final long serialVersionUID = 1L;
	private DocumentIdGenerator id;
	private List<TestDocumentItem> documentItems = new ArrayList <TestDocumentItem>();

	public TestDocument(){

	}

	@Id
	public DocumentIdGenerator getId(){
		return id;
	}
	public void setId(DocumentIdGenerator id){
		this.id = id;
	}

	@OneToMany(targetEntity = TestDocumentItem.class, cascade=CascadeType.ALL)
	public List <TestDocumentItem> getDocumentItems() {
		return documentItems;
	}
	public void setDocumentItems(List <TestDocumentItem> documentItems) {
		this.documentItems = documentItems;
	}
	public void addDocumentItem(TestDocumentItem documentItem){
		this.documentItems.add(documentItem);
	}
}
 
Hab nun eine Lösung selbst Programmiert.

Ob dies allerdings ein sauberer Lösungsansatz ist kann ich leider nicht sagen,
denn dazu fehlt mir die Erfahrung!

TestDocument
Code:
@Entity(name = "TestDocument")
@Table(name = "doc_TestDocument")
@PersistenceUnit(name="TestDocument")
public class TestDocument implements Serializable{
	private static final long serialVersionUID = 1L;
	private long id;

	public TestDocument(){super();}

	@Id
	public long getId(){
		return id;
	}
	public void setId(long id){
		this.id = id;
	}
}

DocumentIdGenerator
Code:
@Entity(name="DocumentIdGenerator")
@Table(name="local_IdGenerator")
@PersistenceUnit(name="DocumentIdGenerator")
@NamedQuery( name = DocumentIdGenerator.QUERY_NAME_GeneratorByName,
				 query = "SELECT gen FROM DocumentIdGenerator gen WHERE sequenceName = :param")
public class DocumentIdGenerator
implements Serializable{
	private static final long serialVersionUID = -4338849341607873156L;
	public static final String QUERY_NAME_GeneratorByName = "GeneratorByName";

	public static final String DOCTYPE_TESTDOC = "TESTDOC";

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private long id = 0;
	private String sequenceName = "";
	private long sequenceValue = 0;

	protected DocumentIdGenerator (){super();}
	public DocumentIdGenerator (String sequenceName){
		this.setSequenceName(sequenceName);
	}
	public DocumentIdGenerator (String sequenceName, long initialValue){
		this.setSequenceName(sequenceName);
		this.setSequenceValue(sequenceValue);
	}

	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}

	public String getSequenceName() {
		return sequenceName;
	}
	public void setSequenceName(String sequenceName) {
		this.sequenceName = sequenceName;
	}

	public long getSequenceValue() {
		return sequenceValue;
	}
	public void setSequenceValue(long sequenceValue) {
		this.sequenceValue = sequenceValue;
	}

	public synchronized long getNextSequenceValue(){
		sequenceValue++;
		if(sequenceValue < (cutYear(getActialYear())*100000))
			sequenceValue = cutYear(getActialYear())*100000 + 1;
		return sequenceValue;
	}

	public static short getActialYear() {
		return (short)cutYear(Calendar.getInstance(Locale.GERMANY).get(Calendar.YEAR));
	}
	public static short cutYear(int year){
		return (short)(year-=((year/100)*100));
	}
}

TestServiceImpl:
Code:
@Stateless
@Remote(TestService.class)
public class TestServiceImpl <T, PK extends Serializable>
extends GenericDaoImpl <TestDocument, DocumentIdGenerator, Entity>
implements TestService{
	public synchronized TestDocument create(TestDocument doc){
		DocumentIdGenerator idGen = findGeneratorByName(DocumentIdGenerator.DOCTYPE_TESTDOC);
		if(idGen == null){
			idGen = createDocumentIdGenerator(idGen);
		}
		doc.setId(idGen.getNextSequenceValue());
		return super.create(doc);
	}

	public TestServiceImpl() {
		super(TestDocument.class);
	}

	@SuppressWarnings("unchecked")
	public DocumentIdGenerator findGeneratorByName(String param) {
		Query res = super.getEntityManager().createNamedQuery(DocumentIdGenerator.QUERY_NAME_GeneratorByName);
		res.setParameter("param", param);
		List <DocumentIdGenerator> l = res.getResultList();
		if(l.isEmpty())
			return null;
		return l.get(0);
	}

	public DocumentIdGenerator createDocumentIdGenerator(DocumentIdGenerator generator){
		generator = new DocumentIdGenerator(DocumentIdGenerator.DOCTYPE_TESTDOC, 800000);
		getEntityManager().persist(generator);
		getEntityManager().flush();
		return generator;
	}
}
 

Neue Beiträge

Zurück