2023-09-17 22:13:42 +03:00
package Common.Database ;
2024-10-07 14:22:52 +03:00
import Common.CommonConstants ;
2024-10-07 00:58:29 +03:00
import Common.Database.Objects.DBObject ;
import Common.Database.Objects.iDBObject ;
2024-10-14 15:19:13 +03:00
import Common.Database.Tables.DBTable ;
import Common.Database.Tables.DataSet ;
2024-10-16 00:04:36 +03:00
import Common.Passes.PassCode_ ;
2024-10-14 15:19:13 +03:00
import Common.Utils.Utils_ ;
2023-09-17 22:13:42 +03:00
import java.io.File ;
import java.util.LinkedHashMap ;
import java.util.Vector ;
//самый общий интерфейс базы данных, независимо от реализации.
public abstract class Database {
//------------------------------
2024-10-17 17:22:33 +03:00
protected LinkedHashMap < Class < ? extends DBObject > , DBTable > tables = new LinkedHashMap < > ( ) ; //таблицы
2023-09-17 22:13:42 +03:00
protected File file = null ;
public Database ( File file_in ) {
file = file_in ;
}
2024-10-17 17:22:33 +03:00
public < T extends DBObject > DBTable < ? , T > getTable ( Class < T > tableClass ) {
return tables . get ( tableClass ) ;
}
2023-09-17 22:13:42 +03:00
public File getFile ( ) {
return file ;
}
public void setFile ( File file_in ) {
file = file_in ;
}
//<editor-fold desc="Общая часть">
public void Connect ( ) throws Exception {
// UI.Print(DebugPrintLevel.Database, "соединение с базой данных " + file.getAbsolutePath());
connect ( ) ;
}
public void prepareTablesStatements ( ) throws Exception {
}
public void Disconnect ( ) throws Exception {
// UI.Print(DebugPrintLevel.Database, "закрытие соединения с базой данных " + file.getAbsolutePath());
disconnect ( ) ;
}
public void BeginTransaction ( ) throws Exception {
// UI.Print(DebugPrintLevel.Database, "BEGIN TRANSACTION:");
beginTransaction ( ) ;
}
public void Commit ( ) throws Exception {
// UI.Print(DebugPrintLevel.Database, "COMMIT");
commit ( ) ;
}
public void CreateAllTables ( ) throws Exception {
BeginTransaction ( ) ;
initAllTables ( ) ; // все добавления новых таблиц - туть.
for ( DBTable table : tables . values ( ) ) {
CreateTable ( table ) ;
table . setDb ( this ) ;
}
Commit ( ) ;
}
//схема как с проходами. в методе initAllTables добавляем все таблицы через уникальные конструкторы
public void addTable ( DBTable table ) {
tables . put ( table . d , table ) ;
}
public void Synchronize ( ) throws Exception {
BeginTransaction ( ) ;
for ( DBTable table : tables . values ( ) )
LoadAll ( table ) ;
Init ( ) ; //перегружаемая часть синхронизации.
Commit ( ) ;
}
public void LoadAllTablesWithoutInit ( ) throws Exception {
BeginTransaction ( ) ;
for ( DBTable table : tables . values ( ) )
LoadAll ( table ) ;
Commit ( ) ;
}
public < K , D extends DBObject > void LoadAll ( DBTable < K , D > table ) throws Exception {
table . Data . clear ( ) ;
loadAll ( table ) ;
}
public DBObject Insert ( DBObject o ) throws Exception {
DBTable table = tables . get ( o . getClass ( ) ) ;
insert ( table , o ) ;
table . Data . put ( o . getPK ( ) , o ) ;
return o ;
}
2023-11-23 01:00:08 +03:00
//метод для вставки в серверную базу.
public DBObject InsertS ( DBObject object ) throws Exception {
DBTable table = tables . get ( object . getClass ( ) ) ;
if ( ! ( object instanceof iDBObject ) & & table . Data . containsKey ( object . getPK ( ) ) )
2024-10-11 00:00:30 +03:00
throw new RepositoryRefuseException ( " Таблица " + Utils_ . Brackets ( table . Name ) + " уже содержит объект с ключом " + Utils_ . Brackets ( object . getPK ( ) . toString ( ) ) ) ;
2023-11-23 01:00:08 +03:00
insert ( table , object ) ;
table . Data . put ( object . getPK ( ) , object ) ;
return object ;
2023-09-17 22:13:42 +03:00
}
// не работает с автоинкрементом.
public DBObject UpdateWithCheck ( DBObject to_update ) throws Exception {
DBTable table = tables . get ( to_update . getClass ( ) ) ;
if ( table . Data . containsKey ( to_update . getPK ( ) ) ) {
DBObject o = ( DBObject ) table . Data . get ( to_update . getPK ( ) ) ;
o . SynchronizeFields ( to_update ) ;
update ( table , o ) ;
return o ;
} else {
insert ( table , to_update ) ;
table . Data . put ( to_update . getPK ( ) , to_update ) ;
return to_update ;
}
}
public DBObject DeleteWithCheck ( DBObject to_delete ) throws Exception {
DBTable table = tables . get ( to_delete . getClass ( ) ) ;
if ( table . Data . containsKey ( to_delete . getPK ( ) ) ) {
DBObject o = ( DBObject ) table . Data . get ( to_delete . getPK ( ) ) ;
delete ( table , o ) ;
table . Data . remove ( o . getPK ( ) ) ;
return o ;
} else
2024-10-11 00:00:30 +03:00
throw new RepositoryRefuseException ( " Таблица " + Utils_ . Brackets ( table . Name ) + " не содержит объект с ключом " + Utils_ . Brackets ( to_delete . getPK ( ) . toString ( ) ) ) ;
2023-09-17 22:13:42 +03:00
}
2023-11-15 01:16:16 +03:00
public DBObject DeleteByPK ( Class object_class , Object key ) throws Exception {
DBTable table = tables . get ( object_class ) ;
if ( table . Data . containsKey ( key ) ) {
DBObject o = ( DBObject ) table . Data . get ( key ) ;
delete ( table , o ) ;
table . Data . remove ( key ) ;
return o ;
} else
2024-10-11 00:00:30 +03:00
throw new RepositoryRefuseException ( " Таблица " + Utils_ . Brackets ( table . Name ) + " не содержит объект с ключом " + Utils_ . Brackets ( key . toString ( ) ) ) ;
2023-11-15 01:16:16 +03:00
}
2023-09-17 22:13:42 +03:00
// не работает с автоинкрементом.
public DBObject getObjectCopyByPK ( Class table_class , Object pk ) throws Exception {
DBTable table = tables . get ( table_class ) ;
Object res_ = table_class . newInstance ( ) ;
DBObject res = ( DBObject ) res_ ;
if ( table . Data . containsKey ( pk ) ) {
DBObject original = ( DBObject ) table . Data . get ( pk ) ;
res . SynchronizeFields ( original ) ;
} else {
table_class . getField ( table . getPKName ( ) ) . set ( res , pk ) ; //инче просто синхроним пк. и вставляем
insert ( table , res ) ;
}
return res ;
}
public boolean checkObjectExistense ( Class table_class , Object pk ) throws Exception {
DBTable table = tables . get ( table_class ) ;
return table . containsKey ( pk ) ;
}
public Vector < Object > getObjectsCopies ( Class table_class , Vector < Object > keys ) {
Vector < Object > res = new Vector < > ( ) ;
DBTable table = tables . get ( table_class ) ;
for ( Object key : keys )
if ( table . containsKey ( key ) )
res . add ( table . Data . get ( key ) ) ;
return res ;
}
public void Delete ( DBObject o ) throws Exception {
DBTable table = tables . get ( o . getClass ( ) ) ;
delete ( table , o ) ;
table . Data . remove ( o . getPK ( ) ) ;
}
public void DeleteAll ( Class < ? extends DBObject > c ) throws Exception {
DBTable table = tables . get ( c ) ;
deleteAll ( table ) ;
table . Data . clear ( ) ;
}
//не вполне обычный случай. подразумевается что поле объекта изменено
//этот же метод закрепляет изменение в бд
//в дальнейшем возможно сделать новое значение поля 2 параметром метода?
public void Update ( DBObject o ) throws Exception {
DBTable table = tables . get ( o . getClass ( ) ) ;
update ( table , o ) ;
}
public void ResetAI ( Class < ? extends DBObject > c ) throws Exception {
resetAI ( tables . get ( c ) ) ;
}
//</editor-fold>
//<editor-fold desc="работа с внешними ключами">
public < O extends DBObject , F extends DBObject > Vector < DBObject > getVectorByFK ( O owner , Class < F > fk_class ) {
Vector < DBObject > res = new Vector < > ( ) ;
try {
for ( Object o : tables . get ( fk_class ) . Data . values ( ) ) {
if ( fk_class . getField ( owner . getFKName ( ) ) . get ( o ) . equals ( owner . getPK ( ) ) ) res . add ( ( DBObject ) o ) ;
}
} catch ( Exception e ) {
2024-10-11 00:00:30 +03:00
Utils_ . MainLog . PrintException ( e ) ;
2023-09-17 22:13:42 +03:00
}
return res ;
}
public < F extends DBObject > void DeleteByFK ( DBObject master , Class < F > fk_class ) throws Exception {
Vector < DBObject > to_delete = getVectorByFK ( master , fk_class ) ;
BeginTransaction ( ) ;
for ( DBObject object : to_delete )
Delete ( object ) ;
Commit ( ) ;
}
//-----------
public < F extends DBObject > void DropByFK ( DBObject master , Class < F > fk_class ) throws Exception {
Vector < DBObject > to_drop = getVectorByFK ( master , fk_class ) ;
BeginTransaction ( ) ;
for ( DBObject object : to_drop ) {
fk_class . getField ( master . getFKName ( ) ) . set ( object , master . getEmptyFK ( ) ) ;
Update ( object ) ;
}
Commit ( ) ;
}
public < K , O extends DBObject , F extends DBObject > LinkedHashMap < K , F > getMapByFK ( O owner , Class < F > fk_class , Class < K > key_class ) {
LinkedHashMap < K , F > res = new LinkedHashMap < > ( ) ;
try {
for ( Object o : tables . get ( fk_class ) . Data . values ( ) ) {
F f = ( F ) o ;
if ( fk_class . getField ( owner . getFKName ( ) ) . get ( f ) . equals ( owner . getPK ( ) ) ) res . put ( ( K ) f . getPK ( ) , f ) ;
}
} catch ( Exception e ) {
2024-10-11 00:00:30 +03:00
Utils_ . MainLog . PrintException ( e ) ;
2023-09-17 22:13:42 +03:00
}
return res ;
}
public < O extends DBObject , F extends iDBObject > LinkedHashMap < Integer , F > getMapByFKi ( O owner , Class < F > fk_class ) {
return getMapByFK ( owner , fk_class , java . lang . Integer . class ) ;
}
//-
public < O extends DBObject , F extends DBObject > Vector < String > getVectorStringByFK ( O owner , Class < F > fk_class ) {
Vector < String > res = new Vector < > ( ) ;
try {
for ( Object o : tables . get ( fk_class ) . Data . values ( ) ) {
if ( fk_class . getField ( owner . getFKName ( ) ) . get ( o ) . equals ( owner . getPK ( ) ) ) res . add ( o . toString ( ) ) ;
}
} catch ( Exception e ) {
2024-10-11 00:00:30 +03:00
Utils_ . MainLog . PrintException ( e ) ;
2023-09-17 22:13:42 +03:00
}
return res ;
}
//безопасное получение объекта по первичному ключу.
public < O extends DBObject > O getByPK ( Class < O > class_in , Object pk , Object undefined_pk ) {
return ( ( ! pk . equals ( undefined_pk ) ) & & tables . get ( class_in ) . Data . containsKey ( pk ) ) ?
( O ) ( tables . get ( class_in ) . Data . get ( pk ) ) : null ;
}
public < O extends iDBObject > O getById ( Class < O > class_in , int pk ) {
2024-10-07 14:22:52 +03:00
return getByPK ( class_in , pk , CommonConstants . Nan ) ;
2023-09-17 22:13:42 +03:00
}
public < G , O extends DBObject , F extends DBObject > LinkedHashMap < G , F > getByFKAndGroupBy ( O owner , Class < F > fk_class , String group_field , Class < G > group_class ) {
LinkedHashMap < G , F > res = new LinkedHashMap < > ( ) ;
try {
for ( Object o : tables . get ( fk_class ) . Data . values ( ) ) {
F f = ( F ) o ;
if ( fk_class . getField ( owner . getFKName ( ) ) . get ( f ) . equals ( owner . getPK ( ) ) )
res . put ( ( G ) ( fk_class . getField ( group_field ) . get ( f ) ) , f ) ;
}
} catch ( Exception e ) {
2024-10-11 00:00:30 +03:00
Utils_ . MainLog . PrintException ( e ) ;
2023-09-17 22:13:42 +03:00
}
return res ;
}
//</editor-fold>
//<editor-fold desc="Перегружаемая часть">
//-
protected abstract void connect ( ) throws Exception ;
protected abstract void disconnect ( ) throws Exception ;
//-
protected abstract void beginTransaction ( ) throws Exception ;
protected abstract void commit ( ) throws Exception ;
//-
protected abstract boolean TableExists ( DBTable table ) throws Exception ;
protected abstract void CreateTable ( DBTable table ) throws Exception ;
protected abstract < K , D extends DBObject > void loadAll ( DBTable < K , D > table ) throws Exception ;
protected abstract void initAllTables ( ) throws Exception ;
//перегружаемая часть синхронизации
public void Init ( ) throws Exception {
}
protected abstract void insert ( DBTable table , DBObject o ) throws Exception ;
protected abstract void delete ( DBTable table , DBObject o ) throws Exception ;
protected abstract void deleteAll ( DBTable table ) throws Exception ;
protected abstract void update ( DBTable table , DBObject o ) throws Exception ;
protected abstract void resetAI ( DBTable table ) throws Exception ;
//-
public void SaveLastSelections ( ) {
for ( DataSet dataSet : tables . values ( ) )
dataSet . SaveLastSelections ( ) ;
}
public void RestoreLastSelections ( ) {
for ( DataSet dataSet : tables . values ( ) )
dataSet . RestoreLastSelections ( ) ;
}
2023-11-16 16:20:20 +03:00
//---
2024-10-16 00:04:36 +03:00
public abstract PassCode_ getSynchronizePassCode ( ) ; //если бд есть на сервере.
2023-09-17 22:13:42 +03:00
}