This paper introduces the design and implementation of the core functions of panda Orm (that is, to add a simple annotation to the entity for the function of adding and checking operations).
An introduction to the whole idea
1, first understand the project structure as follows, note that all the packages are in the SRC directory under the Panda.orm, the configuration file config.properties in the SRC directory.
2, annotation is a custom annotation, which is used primarily to add additional information related to primary keys and foreign keys for columns of entity classes. This way, when Panda Orm runs, it knows which columns of the entity class are the primary key and the foreign key corresponding column.
3,database the database-related classes, where the core is a DataTable class, the DataTable class is instantiated through the class class of entity classes, and the class information of the entity is read by reflection. The DataTable ultimately saves the table structure information for the entity class .
The ioperation in the 4,operation package defines the methods that all database operation classes should implement, entityoperation the class of the entity class to instantiate, and can produce an object for the deletion of the entity class object. Entityoperation is to read the Entity class table structure information through the DataTable, and then the structure information in the DataTable is translated into the corresponding SQL statement.
5,exception is the exception class, is the custom of several exceptions, relatively simple no longer detailed. Under the Util are some tools, the log class, does not belong to this article core content also does not affect the understanding, no longer launches the explanation.
In short, through the annotation Description entity-table correspondence relation, through the DataTable records the entity structure information, through the entityoperation the structure information unifies the operation request translates into the SQL statement and executes.
Two, annotation design and implementation
Divide the columns into three categories, the primary key columns (whether you want the markup to grow since you are writing the master key when you generate the INSERT statement), the Foreign-key column (you need to find the column of the table that the foreign key points to from the note), and the normal column (no annotations).
The specific code is as follows:
Package panda.orm.annotation;
Custom enumeration type, which is used only to mark whether the primary key column has grown since, note that the annotation does not support Boolean type arguments, so this is the worst public
enum AutoIncrement {
true,false
}
Package panda.orm.annotation;
Import java.lang.annotation.*;
@Target (Elementtype.field)//note is used to describe the
@Retention (retentionpolicy.runtime)//notes that are available at run time
@Documented//Can be Java Doc public
@interface Key {public
autoincrement value () default autoincrement.true;//annotation parameter AutoIncrement, The default value is self-growth
}
package panda.orm.annotation;
Import java.lang.annotation.*;
@Target (Elementtype.field)
@Retention (retentionpolicy.runtime)
@Documented public
@interface ForeignKey {public
String value () default "";//value parameter represents the column name of the table to which the foreign key refers
}
implementation of the solid class structure parser DataTable
Note that the DataTable has three columns, the normal column, the primary key column, the foreign key column, and the code (omitting the Get Set method):
Package panda.orm.database;
public class Column {//Normal column
//Column name
protected String;
Column value
protected String value;
}
The public class KeyColumn extends column{
//Primary key column has more than one self-growing attribute
protected AutoIncrement autoincrement;
}
The public class Foreignkeycolumn extends column{
//Foreign key column contains the primary table name and the primary table foreign key corresponding column name
protected String foreigntablename;
protected String foreigncolumnname;
}
The point here is how the DataTable class reads the entity class structure and transforms it into a table structure, as follows:
public class DataTable {//The variable holds the information for the class of the corresponding entity of the table protected class Objclass; Table structure variable protected String tablename;//table name protected KeyColumn keycolumn=new keycolumn ();//primary key column information protected set< ; Foreignkeycolumn> fkeycolumns=new hashset<foreignkeycolumn> ();//foreign key column information protected set<column> columns= The new hashset<column> ()//Normal column information//constructor initializes the table structure public DataTable (class Objclass) {This.objclass=o by the entity class structure
Bjclass;
Tablename=objclass.getsimplename (); field[] fields = Objclass.getdeclaredfields ()//Entity class Property list for (Field field:fields) {if (field.isannotatio
Npresent (Key.class)) {keycolumn=new keycolumn ();
Keycolumn.setname (Field.getname ());//Get column name Key Mkey = (key) field.getannotation (Key.class);
Keycolumn.setautoincrement (Mkey.value ())//Get whether to grow from}else if (Field.isannotationpresent (Foreignkey.class)) { Foreignkeycolumn fkeycolumn=new FOreignkeycolumn ();
ForeignKey Fkey = (ForeignKey) field.getannotation (Foreignkey.class); Fkeycolumn.setname (Field.getname ());//Get Column name Fkeycolumn.setforeigntablename (Field.gettype (). Getsimplename ()) ;//foreign key corresponding primary table name Fkeycolumn.setforeigncolumnname (Fkey.value ());//foreign key corresponds to the column fkeycolumns.add of the primary table (Fkey
Column);
}else{column column=new column ();
Column.setname (Field.getname ());
Columns.Add (column); } } } }
The table above holds table names, column name information, but some operations, such as adding an entity, modifying an entity, and requiring the column value information of the entity's corresponding column, there is another method datatable.setvalue as follows:
For the Add and update operations, you also need information about the values of each column in the table public void SetValue (Object obj) throws exception{Class Objclass=obj.getclass ()
; if (!objclass.getsimplename (). Equals (tablename)) {throw new objectnotmatchexception ("Entity does not match category", This.getclass ().
GetName (), "Entity and category Mismatch", Objclass.getsimplename (), tablename);
} field[] fields = Objclass.getdeclaredfields ();
for (Field field:fields) {field.setaccessible (true);
if (Field.isannotationpresent (Key.class)) {//Primary key column Keycolumn.setvalue ((String) field.get (obj)); }else if (field.isannotationpresent (Foreignkey.class)) {//Foreign key column logic is more complex, the key is to take the foreign key corresponding to the primary table column values Foreign
Key Fkey = (ForeignKey) field.getannotation (Foreignkey.class);
Object foreignobj=field.get (obj);
Field Foreignfield=foreignobj.getclass (). Getdeclaredfield (Fkey.value ());
Foreignfield.setaccessible (TRUE); for (Foreignkeycolumn C:THIS.FKEycolumns) {if (C.getname (). Equals (Field.getname ())) {C.setvalue ((String) Foreig
Nfield.get (foreignobj)); }}else{for (column c:this.columns) {//Multiple normal columns if (c.getname
(). Equals (Field.getname ())) {C.setvalue ((String) field.get (obj)); }
}
}
}
}
four, generate SQL statement by Table structure class DataTable
Using a simple factory class to generate general statements can be commonly used as follows, this part of the logic is relatively simple without comment
Package panda.orm.database;
Import panda.orm.annotation.AutoIncrement; public class Sqlfactory {public static String Createselectpagesql (DataTable table,int offset,int rows) {Strin
Gbuilder sb=new StringBuilder ();
Sb.append ("SELECT * from" +table.gettablename ()); For (Foreignkeycolumn f:table.getfkeycolumns ()) {//To prevent the table in which the foreign key is located, add this business logic sb.append ("," +f.getforeignt
Ablename () + "as Foreign_" +f.getforeigntablename ());
} sb.append ("where 1=1"); For (Foreignkeycolumn f:table.getfkeycolumns ()) {Sb.append ("and" +table.gettablename () + "." +f.getname () + "=foreign_" +f.getforeigntablename () + "."
+f.getforeigncolumnname ());
} sb.append ("Order By" +table.getkeycolumn (). GetName () + "Limit" +offset+ "," +rows);
return sb.tostring ();
public static String Createselectallsql (DataTable table) {StringBuilder sb=new StringBuilder (); Sb.append ("SELECT * from" +table.gettablename ()); For (Foreignkeycolumn f:table.getfkeycolumns ()) {Sb.append ("," +f.getforeigntablename () + "as Foreign_" +f.getFore
Igntablename ());
} sb.append ("where 1=1"); For (Foreignkeycolumn f:table.getfkeycolumns ()) {Sb.append ("and" +table.gettablename () + "." +f.getname () + "=foreign_" +f.getforeigntablename () + "."
+f.getforeigncolumnname ());
return sb.tostring ();
public static String Createselectonesql (DataTable table,string key) {StringBuilder sb=new StringBuilder ();
Sb.append ("SELECT * from" +table.gettablename ()); For (Foreignkeycolumn f:table.getfkeycolumns ()) {Sb.append ("," +f.getforeigntablename () + "as Foreign_" +f.getFore
Igntablename ());
} sb.append ("where 1=1"); For (Foreignkeycolumn f:table.getfkeycolumns ()) {Sb.append ("and" +table.gettablename () + "." +f.getname () + "=foreign_" +f.getforeigntablename () + "."
+f.getforeigncolumnname ());
} Sb.append ("and" +table.getkeycolumn (). GetName () + "= '" +key+ "");
return sb.tostring ();
public static String Createaddsql (DataTable table) {StringBuilder sb=new StringBuilder ();
Sb.append ("INSERT INTO" +table.gettablename () + "(");
if (Table.getkeycolumn (). Getautoincrement () ==autoincrement.false) {sb.append (Table.getkeycolumn (). GetName ());
For (Column c:table.getcolumns ()) {Sb.append (C.getname () + ",");
For (Column c:table.getfkeycolumns ()) {Sb.append (C.getname () + ",");
} Sb.deletecharat (Sb.length ()-1);
Sb.append (") VALUES (");
if (Table.getkeycolumn (). Getautoincrement () ==autoincrement.false) {sb.append (Table.getkeycolumn (). GetValue ());
For (Column c:table.getcolumns ()) {Sb.append ("'" +c.getvalue () + "',");
For (Column c:table.getfkeycolumns ()) {Sb.append ("'" +c.getvalue () + "',"); } Sb.deletecharat (Sb.length ()-1);
Sb.append (")");
return sb.tostring ();
public static String Createupdatesql (DataTable table) {StringBuilder sb=new StringBuilder ();
Sb.append ("Update" +table.gettablename () + "set");
For (Column c:table.getcolumns ()) {Sb.append (C.getname () + "= '" +c.getvalue () + "',");
For (Column c:table.getfkeycolumns ()) {Sb.append (C.getname () + "= '" +c.getvalue () + "',");
} Sb.deletecharat (Sb.length ()-1);
Sb.append ("where" +table.getkeycolumn (). GetName () + "= '" +table.getkeycolumn (). GetValue () + "'");
return sb.tostring (); public static String Createselectcountsql (DataTable table) {String sql= select count ("+table.getkeycolumn").
GetName () + ") as Count from" +table.gettablename ();
return SQL; public static String Createdeletesql (DataTable table,string key) {String sql= ' delete from ' +table.gettablena Me () + "W"Here "+table.getkeycolumn (). GetName () +" = ' "+key+" ";
return SQL;
}
}
five, using entityoperation to encapsulate database entity operations
Direct Source:
Package panda.orm.operation;
Import Java.lang.reflect.Field;
Import Java.sql.ResultSet;
Import java.util.ArrayList;
Import Java.util.Date;
Import java.util.List;
Import Panda.orm.annotation.ForeignKey;
Import panda.orm.database.DataTable;
Import Panda.orm.database.MySQLHandler;
Import Panda.orm.database.SqlFactory;
Import panda.orm.exception.BaseException;
Import panda.orm.exception.SqlExcuteException;
public class Entityoperation implements ioperation{protected DataTable table;
Public entityoperation (Class objclass) {table=new DataTable (objclass);
@Override public int SelectCount () {Mysqlhandler hand=new mysqlhandler ();
ResultSet Rs=null;
int re=0;
String sql=sqlfactory.createselectcountsql (table);
try {rs=hand.query (SQL);
while (Rs.next ()) {Re=rs.getint ("count");
return to re; The catch (Exception ex) {new Sqlexcuteexception (ex.geTmessage (), This.getclass (). GetName (), "SQL execution exception", SQL);
return 0;
}finally{Hand.saygoodbye ();
@Override public Object SelectOne (String key) {Mysqlhandler hand=new mysqlhandler ();
ResultSet Rs=null;
Object One=null;
String Sql=sqlfactory.createselectonesql (Table,key);
try {rs=hand.query (SQL);
while (Rs.next ()) {One=objectfromselectresult (RS);
return one;
The catch (Exception ex) {new Sqlexcuteexception (Ex.getmessage (), This.getclass (). GetName (), "SQL execution exception", SQL);
return null;
}finally{Hand.saygoodbye (); The public object Objectfromselectresult (ResultSet rs) throws exception{Object Obj=table.getobjclass (). NE
Winstance ();
field[] fields = Table.getobjclass (). Getdeclaredfields ();
for (Field field:fields) {field.setaccessible (true); if (Field.isannotationpresent (Foreignkey.class)) {ForeignKey Fkey = (ForeignKey) Field.getannota
tion (foreignkey.class);
String Classname=field.gettype (). toString (). Replace ("Class", "");
Object foreignobj=class.forname (className). newinstance ();
Field.set (obj, foreignobj);
Field[] Fkeyfields=foreignobj.getclass (). Getdeclaredfields ();
for (Field fkeyfield:fkeyfields) {fkeyfield.setaccessible (true); if (!fkeyfield.isannotationpresent (Foreignkey.class)) {String foreigncolumnname= ' foreign_ ' +class.fo Rname (ClassName). Getsimplename () + "."
+fkeyfield.getname ();
Fkeyfield.set (Foreignobj, rs.getstring (foreigncolumnname));
}}else{field.set (obj, rs.getstring (Field.getname ()));
} return obj;
} @OverridePublic List SelectAll () {Mysqlhandler hand=new mysqlhandler ();
ResultSet Rs=null;
ArrayList list=new ArrayList ();
String sql=sqlfactory.createselectallsql (table);
try {rs=hand.query (SQL);
while (Rs.next ()) {Object one=objectfromselectresult (RS);
List.add (one);
} return list;
The catch (Exception ex) {new Sqlexcuteexception (Ex.getmessage (), This.getclass (). GetName (), "SQL execution exception", SQL);
return null;
}finally{Hand.saygoodbye ();
@Override public List selectpage (int offset, int rows) {Mysqlhandler hand=new mysqlhandler ();
ResultSet Rs=null;
ArrayList list=new ArrayList ();
String Sql=sqlfactory.createselectpagesql (table,offset,rows);
try {rs=hand.query (SQL); while (Rs.next ()) {Object one=objectfromselectresult (RS);
List.add (one);
} return list;
The catch (Exception ex) {new Sqlexcuteexception (Ex.getmessage (), This.getclass (). GetName (), "SQL execution exception", SQL);
return null;
}finally{Hand.saygoodbye ();
@Override public int Delete (String key) {Mysqlhandler hand=new mysqlhandler ();
String Sql=sqlfactory.createdeletesql (Table,key);
try {int re=hand.execute (SQL);
return re;
The catch (Exception ex) {new Sqlexcuteexception (Ex.getmessage (), This.getclass (). GetName (), "SQL execution exception", SQL);
return 0;
}finally{Hand.saygoodbye (); @Override public int Add (Object obj) {mysq