2023-09-17 22:13:42 +03:00
|
|
|
|
package Common.Database;
|
2023-10-04 22:01:09 +03:00
|
|
|
|
import Common.Constants;
|
2023-09-17 22:13:42 +03:00
|
|
|
|
import Common.Global;
|
|
|
|
|
|
import Common.Utils.Utils;
|
|
|
|
|
|
import Repository.RepositoryRefuseException;
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
|
|
import java.util.Vector;
|
|
|
|
|
|
//самый общий интерфейс базы данных, независимо от реализации.
|
|
|
|
|
|
public abstract class Database {
|
|
|
|
|
|
//------------------------------
|
|
|
|
|
|
public LinkedHashMap<Class<? extends DBObject>, DBTable> tables = new LinkedHashMap<>(); //таблицы
|
|
|
|
|
|
protected File file = null;
|
|
|
|
|
|
public Database(File file_in) {
|
|
|
|
|
|
file = file_in;
|
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
public DBObject InsertWithCheck(DBObject o) throws Exception {
|
|
|
|
|
|
DBTable table = tables.get(o.getClass());
|
|
|
|
|
|
if (!table.Data.containsKey(o.getPK())) {
|
|
|
|
|
|
insert(table, o);
|
|
|
|
|
|
table.Data.put(o.getPK(), o);
|
|
|
|
|
|
} else
|
|
|
|
|
|
throw new RepositoryRefuseException("Таблица " + Utils.Brackets(table.Name) + " уже содержит объект с ключом " + Utils.Brackets(o.getPK().toString()));
|
|
|
|
|
|
return o;
|
|
|
|
|
|
}
|
|
|
|
|
|
public DBObject InsertWithCheck_(DBObject o) throws Exception {
|
|
|
|
|
|
DBTable table = tables.get(o.getClass());
|
|
|
|
|
|
if (!table.Data.containsKey(o.getPK())) {
|
|
|
|
|
|
insert(table, o);
|
|
|
|
|
|
table.Data.put(o.getPK(), o);
|
|
|
|
|
|
return o;
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
// не работает с автоинкрементом.
|
|
|
|
|
|
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
|
|
|
|
|
|
throw new RepositoryRefuseException("Таблица " + Utils.Brackets(table.Name) + " не содержит объект с ключом " + Utils.Brackets(to_delete.getPK().toString()));
|
|
|
|
|
|
}
|
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
|
|
|
|
|
|
throw new RepositoryRefuseException("Таблица " + Utils.Brackets(table.Name) + " не содержит объект с ключом " + Utils.Brackets(key.toString()));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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) {
|
|
|
|
|
|
Global.Log.PrintException(e);
|
|
|
|
|
|
}
|
|
|
|
|
|
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) {
|
|
|
|
|
|
Global.Log.PrintException(e);
|
|
|
|
|
|
}
|
|
|
|
|
|
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) {
|
|
|
|
|
|
Global.Log.PrintException(e);
|
|
|
|
|
|
}
|
|
|
|
|
|
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) {
|
2023-09-29 21:46:08 +03:00
|
|
|
|
return getByPK(class_in, pk, Constants.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) {
|
|
|
|
|
|
Global.Log.PrintException(e);
|
|
|
|
|
|
}
|
|
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|