COMPASSi/trunk/code/inc/Util/include/DataTable.h

627 lines
21 KiB
C
Raw Normal View History

2025-06-25 15:06:42 +08:00
#ifndef _DATA_TABLE_
#define _DATA_TABLE_
#define _INSENSETIVE
#include <QString>
#include <iostream>
#include <assert.h>
#include <vector>
#include <list>
#include <map>
#include <QString>
#include "DataColumn.h"
#include "UtilityGlobal.h"
#include "DataTable.h"
#include "DataSet.h"
using namespace std;
class DataColumnCollection;
class DataRow;
class DataRowCollection;
class DataTable;
enum class data_type{
INTEGER = 1, /* 整型 */
TEXT, /* 字符串 */
REAL, /* 浮点型 */
BLOB, /* 二进制数据 */
};
/* 定义:表示 DataTable或DataRow列的集合.
DataColumnCollection定义 DataTable的架构DataColumn可以包含的数据类型
DataColumnCollection和DataTable是组合关系
DataColumnCollection使用 Add Remove DataColumn
使Count确定集合中的DataColumn对象数 使Contains验证集合中是否存在指定的索引或列名 */
class UTILITY_API DataColumnCollection
{
friend class DataTable;
friend class DataRow;
friend class DataRowCollection;
public:
DataColumn& operator[](int index); //获取或设置指定索引的列
DataColumn& operator[](const QString& column_name); //获取或设置指定列名的列
DataColumn* getColumnDataByColumnName(const QString &column_name);
DataColumn* at(int index);
void Add(DataColumn* p_column); //将指定的 DataColumn 对象添加到 DataColumnCollection
void Add(DataColumn* p_column, int index); //将指定的 DataColumn 对象添加到 DataColumnCollection对应索引处
DataColumn& Add(const QString& column_name); //创建一个具有指定名称的 DataColumn 对象,并将其添加到 DataColumnCollection 中。返回新创建的DataColumn
void Remove(DataColumn& dc); //从DataTable中移除指定的 DataColumn 对象。(需从移除DataRow的DataColumnCollection中移除该列)
void Remove(const QString& column_name); //从集合中移除具有指定名称的 DataColumn 对象(需从移除DataRow的DataColumnCollection中移除该列)
void RemoveAt(int index); //从集合中移除指定索引位置的列(需从移除DataRow的DataColumnCollection中移除该列)
bool Contains(const QString& column_name); //返回集合中是否包含指定列名的列
int Count(); //获取集合中的元素总数
int Count() const; //获取集合中的元素总数
/* .NET 中 clear public 提供,这里沿袭这个做法,但是这个函数极度危险,不要乱用 */
void Clear(); //清除集合中的所有列不清除DataTable
void CopyTo(DataColumnCollection* arr, int index); //将整个集合复制到指定集合中,从该集合内的指定索引处开始复制。
void setFromValue(DataColumnCollection *arr, int index);
//void Table(DataTable* tb);
//DataTable* Table();
bool isHasKeyAndValue(QString column_name,QString value);
DataColumn* getColumnRealValue(const QString& column_name)
{
DataColumn* p = getColumnDataByColumnName(column_name);
return p;
}
bool isColumnValueNull(const QString& column_name)
{
DataColumn* p = getColumnDataByColumnName(column_name);
if (!p)
{
return true;
}
if(p->Value().isNull())
{
return true;
}
return false;
}
template <typename T>
bool getColumnValue(const QString &column_name,T& value)
{
DataColumn* p = getColumnDataByColumnName(column_name);
if (!p) return false;
if constexpr (std::is_same_v<T, int>) {
value = p->toInt();
return true;
}
else if constexpr (std::is_same_v<T, double>) {
value = p->toDouble();
return true;
}
else if constexpr (std::is_same_v<T, bool>) {
value = p->toBool();
return true;
}
else if constexpr (std::is_same_v<T, std::string>) {
value = p->toString().toStdString();
return true;
}
else if constexpr (std::is_same_v<T, QString>) {
value = p->toString();
return true;
}
else {
return false; // Unsupported type
}
}
template <typename T>
T getColumnValue(const QString& column_name)
{
DataColumn* p = getColumnDataByColumnName(column_name);
if (!p) {
// 如果没有找到列名对应的列,返回一个默认值(适用于简单类型)
return T{};
}
// 通用的转换函数
auto convert = [](auto&& value) -> T {
return static_cast<T>(value);
};
// 如果类型是支持的
if constexpr (std::is_same_v<T, int>) {
return convert(p->toInt());
}
else if constexpr (std::is_same_v<T, double>) {
return convert(p->toDouble());
}
else if constexpr (std::is_same_v<T, bool>)
{
if(p->DataType() == QVariant::String )
{
QString data_ = p->Value().toString();
if(data_ == "Y")
{
return true;
}
else
{
return false;
}
}
else if(p->DataType() == QVariant::Bool)
{
return convert(p->toBool());
}
}
else if constexpr (std::is_same_v<T, std::string>) {
return convert(p->toString().toStdString());
}
else if constexpr (std::is_same_v<T, QString>) {
return convert(p->toString());
}
else {
// 不支持的类型可以抛出异常或者返回std::optional来表示错误
static_assert(std::is_same_v<T, T>, "Unsupported type");
return T{}; // 或者 return std::nullopt; 这取决于你如何处理不支持的类型
}
}
template <typename T>
bool setColumnValue(const QString &column_name,T value)
{
DataColumn* p = getColumnDataByColumnName(column_name);
if (!p)
{
return false;
}
if constexpr (std::is_same_v<T, int>) {
p->Value(value);
return true;
}
else if constexpr (std::is_same_v<T, double>) {
p->Value(value);
return true;
}
else if constexpr (std::is_same_v<T, bool>)
{
if(value == true)
{
p->Value("Y");
}
else
{
p->Value("N");
}
return true;
}
else if constexpr (std::is_same_v<T, std::string>)
{
QString str = QString::fromStdString(value);
p->Value(str);
return true;
}
else if constexpr (std::is_same_v<T, QString>) {
p->Value(value);
return true;
}
return true;
}
public:
void setParentTable(DataTable* p)
{
_table = p;
}
private:
DataColumnCollection(); //初始化DataRow使用
DataColumnCollection(DataTable* initialized_table); // a null table use this to initialize a null dataClumnCollection.
DataColumnCollection(const DataColumnCollection& other);
DataColumnCollection& operator=(const DataColumnCollection& other);
~DataColumnCollection();
void Add(DataColumn* dc, int index, DataColumnCollection* collect);
void RemoveAt(int index, DataColumnCollection* collect); //只移除DataColumnCollection指定索引处的列
void print(); //打印列名
private:
DataTable* _table = nullptr; // the owner of this DataColumnCollection, never free it
// 数据存储量不大,同时查询频繁,效率优先,用双索引
vector<DataColumn*> _column_list; // 存column和Idx关系
map<QString, DataColumn*> _name_map; // 存column和name关系
};
/* 定义:表示 DataTable 中的一行数据。
DataRow和 DataColumn是主要DataTable组件
DataRow管理该行的DataColumnCollectionDataColumn即是一个数据单元
使使[]DataColumn的值
DataRow使 DataTable的 NewRow方法 DataRow后使Add DataRow DataRowCollection
eg:DataRow* dr=dt.NewRow();dt.Rows().Add(dr); */
class UTILITY_API DataRow
{
friend class DataTable;
friend class DataRowCollection;
friend class DataColumnCollection;
public:
DataRow(const DataRow& other);
DataRow& operator=(const DataRow& other);
~DataRow();
void updataColumns(DataColumnCollection* p)
{
if(p)
{
DataColumnCollection* _columns_tmp = new DataColumnCollection(*(p));
_columns_tmp->setFromValue(_columns,_columns->Count());
DELETE_PTR(_columns)
_columns = _columns_tmp;
}
}
public:
DataTable* Table(); //获取该行拥有其架构的 DataTable
DataColumnCollection& Columns(); //获取或设置改行的DataColumnCollection
DataColumn* getColumDataByIndex(int index);
DataColumn& operator[](int index); //获取或设置该行中指定索引的某列
const DataColumn& operator[](int index) const; //获取该行中指定索引的某列
DataColumn& operator[](const QString& column_name); //获取或设置该行中指定列名的某列
const DataColumn& operator[] (const QString &column_name) const; //获取该行中指定列名的某列
DataColumn* getColumnDataByColumnName(const QString &columnName);
bool isHasKeyAndValue(QString columnName,QString value);
int getColumnCount()
{
return _columns->Count();
}
template <typename T>
bool setColumnValue(const QString &column_name,T value)
{
return _columns->setColumnValue(column_name,value);
}
template <typename T>
bool getColumnValue(const QString &column_name,T& value)
{
return _columns->getColumnValue(column_name,value);
}
template <typename T>
T getColumnValue(const QString &column_name)
{
return _columns->getColumnValue<T>(column_name);
}
DataColumn* getColumnRealValue(const QString& column_name)
{
return _columns->getColumnRealValue(column_name);
}
bool isColumnValueNull(const QString& column_name)
{
return _columns->isColumnValueNull(column_name);
}
void Refresh();
private:
DataRow(); //为DataTable提供的构造函数
//void Remove(DataColumn& dc);
//void RemoveAt(int index);
DataColumnCollection* _columns = nullptr; // 数据信息
DataTable* _table = nullptr; // 位置信息
// int _row_id = 0; // 位置信息 // 单独管理行号太麻烦了row也没地方用 // 用list idx取代行号
#ifdef QT_DEBUG
vector<string> _str_list;
#endif
};
/* 定义:表示 DataTable 的行的集合。
DataColumnCollection定义表的架构 DataRowCollection
DataRowCollection和DataTable是组合关系
DataRow不可脱离DataTable独立存在DataTable方法新建DataRow eg:DataRow* dr=dt.NewRow();dt.Rows().Add(dr);
Add Remove DataRowCollection中插入和删除 DataRow
使[] */
class UTILITY_API DataRowCollection
{
friend class DataTable;
friend class DataColumnCollection;
public:
DataRow& operator[](int index); //获取或设置指定索引处的行
DataRow* getRowDataByIndex(int index);
void Add(DataRow* p_row); //将指定的 DataRow 添加到 DataRowCollection 对象中,并给行号赋值
void Remove(DataRow* p_row); //从集合中移除指定的 DataRow。
void RemoveAt(int index); //从集合中移除指定索引处的行
/* .NET 中 clear public 提供,这里沿袭这个做法,但是这个函数极度危险,不要乱用 */
void Clear(); //清除所有行的集合
int Count() const; //获取该集合中 DataRow 对象的总数
void setParentTable(DataTable* p)
{
_table = p;
}
private:
DataRowCollection() = delete;
DataRowCollection(DataTable* initialized_table); // a null table use this to initialize a null dataRowCollection.
DataRowCollection(const DataRowCollection& other);
DataRowCollection& operator=(const DataRowCollection& other);
~DataRowCollection();
private:
vector<DataRow*> _raw_list;
DataTable* _table = nullptr;
};
class UTILITY_API DataTableSplitBody //DataTable 分身纯粹是对 DataTable 内存数据查询 返回DataTable row的内存指针实施获取数据和修改value值
{
friend class DataColumnCollection;
friend class DataRowCollection;
friend class DataTableCollection;
friend class DataSet;
public:
DataTableSplitBody()
{
clear();
}
~DataTableSplitBody()
{
clear();
}
public:
int getRowCount()
{
return _raw_list.size();
}
DataRow* getRowDataByIndex(int index)
{
if(index >=0 && index < _raw_list.size())
{
return _raw_list[index];
}
return nullptr;
}
template <typename T>
bool getFirstRowColumnValue(const QString &column_name,T& value)
{
DataRow* pRow = getRowDataByIndex(0);
if(!pRow)
{
return false;
}
return pRow->getColumnValue(column_name,value);
}
template <typename T>
T getFirstRowColumnValue(const QString &column_name)
{
DataRow* pRow = getRowDataByIndex(0);
if(!pRow)
{
return T{};
}
return pRow->getColumnValue<T>(column_name);
}
template <typename T>
T getLastRowColumnValue(const QString &column_name)
{
int iCount = getRowCount();
DataRow* pRow = getRowDataByIndex(iCount - 1);
if(!pRow)
{
return T{};
}
return pRow->getColumnValue<T>(column_name);
}
template <typename T>
bool setFirstRowColumnValue(const QString &column_name,T value)
{
DataRow* pRow = getRowDataByIndex(0);
if(!pRow)
{
return false;
}
return pRow->setColumnValue<T>(column_name,value);
}
void addRow(DataRow* p)
{
if(p)
{
_raw_list.emplace_back(p);
}
}
void clear()
{
vector<DataRow*> t;
_raw_list.swap(t);
}
void setTableName(QString name)
{
m_table_name = name;
}
QString getTableName()
{
return m_table_name;
}
private:
QString m_table_name;
vector<DataRow*> _raw_list;
};
/* 定义:内存中数据的一个表
DataTable可脱离DataSet单独存在DataSet.DataSet数据库连接()DataTable
DataTable和DataRowCollectionDataColumnCollection是组合关系
DataTable通过DataRowCollection和DataColumnCollection提供的AddRemove等方法管理表的行和列
DataRow不可脱离DataTable独立存在DataTable方法新建DataRow eg:DataRow* dr=dt.NewRow();
DataTable拷贝时 DataTable tablenameDatasetQSqldatabase\QSqlTableModel皆保持原状
使[]使[][].使=
Clearempty等方法清除和判空
Select_bysql方法获取筛选和排序后拷贝的DataTable
使Select方法
.net不同之处在于数据库数据同步部分
DataTable可使用connect建立与数据库的连接,
table或者所属DataSet并未连接DataSet有权与数据库文件建立连接
DataSet存在连接使
qsqltablemodel
table_to_dbdb_to_table
*/
class UTILITY_API DataTable
{
friend class DataColumnCollection;
friend class DataRowCollection;
friend class DataTableCollection;
friend class DataSet;
public:
DataTable(); //创建空表
DataTable(const QString& table_name, const QString& sql_filter_exp);
DataTable(const QString& table_name); //根据指定表名创建空表
DataTable(QSqlTableModel* table_model); //根据QSqltableModel创建表并同步表名\数据\数据库连接
DataTable(const DataTable& other);
DataTable& operator=(const DataTable& other); //只拷贝数据dataset和connect皆置为默认值用户可拷贝结束后自行设置
~DataTable();
public:
void updateDataFromOther(DataTable& other);
QString get_sql_filter_exp();
DataRow* AddNewRow();
DataRow* NewRow(); //创建与该表具有相同架构的新 DataRow。空表无表结构无法插入行。
DataColumnCollection& Columns(); //获取或设置属于该表的列的集合。
const DataColumnCollection& Columns() const; //获取属于该表的列的集合。
DataRowCollection* getRows();
DataRowCollection& Rows(); //获取或设置属于该表的行的集合。
int getColumnCount();
int getRowCount();
const DataRowCollection& Rows() const; //获取属于该表的行的集合。
QSqlTableModel* Model(); //获取或设置_table_model供开发者使用
QString TableName(); //获取DataTable 的名称。
void TableName(const QString& table_name); //设置 DataTable 的名称。
DataSet* get_dataset(); //获取此表所属的 DataSet。
DataRow& operator[](int index); //获取或设置指定行号的行
DataRow* getRowDataByIndex(int index);
bool isContainsColumn(QString ColumnName);
bool addNewColumn(QString column_name, QVariant::Type column_type);
bool addNewColumn(DataColumn *p_column);
void setParentTable()
{
_dc_collect->setParentTable(this);
_dr_collect->setParentTable(this);
}
template <typename T>
bool getFirstRowColumnValue(const QString &column_name,T& value)
{
DataRow* pRow = _dr_collect->getRowDataByIndex(0);
if(!pRow)
{
return false;
}
return pRow->getColumnValue(column_name,value);
}
template <typename T>
T getFirstRowColumnValue(const QString &column_name)
{
DataRow* pRow = _dr_collect->getRowDataByIndex(0);
if(!pRow)
{
return T{};
}
return pRow->getColumnValue<T>(column_name);
}
template <typename T>
bool setFirstRowColumnValue(const QString &column_name,T value)
{
DataRow* pRow = _dr_collect->getRowDataByIndex(0);
if(!pRow)
{
return false;
}
return pRow->setColumnValue<T>(column_name,value);
}
const DataRow& operator[](int index) const; //获取指定行号的行
/* 用法dt.Select("column1='row81'"); 浮点数需要加小数点int和long不需 限制浮点数只支持查询double
QT5.15.2QVariant和qsqltablemodel的限制无法查询float转为real存入数据库的值float请使用Select_bysql
Select_bysql取代使Select_bysql*/
DataTable Select(const QString& sql_filter_exp);
/* 用法dt.Select("column1=91.0", "column8", Qt::DescendingOrder); 浮点数需要加小数点int和long不需
Select_bysql取代使Select_bysql*/
DataTable Select(const QString& sql_filter_exp, const QString& column_name, Qt::SortOrder order = Qt::SortOrder::AscendingOrder);
/* 用法1dt.Select("where ifstar = 1 and cacap = 'name' order by yf , ElementID");
select * from tablename会在方法里拼接
2,params参数绑定占位符和值float
const QMap<QString, QVariant> params = {
{"age", 1.2f}, //若需要查询float类型需明确指明1.2f.否则C++默认为double
{"name", "yourname"}
};
DataTable result =dt.Select_bysql("WHERE age = :age AND name = :name ORDER BY weight ASC, height ASC", params);*/
DataTable Select_bysql(const QString& sql_exp, const QMap<QString, QVariant> params = QMap<QString, QVariant>());
DataRow* Select_bysql_con_one(const std::string& condition,const std::string& sortColumn = "");
vector<DataRow*> Select_bysql_con(const std::string& condition,const std::string& sortColumn = "");
bool parseCondition(DataRow* row, const std::string& condition);
bool parseSingleCondition(DataRow* row, const std::string& condition);
void removeRow(DataRow *p_row); //删除其中一行 index 该行的原始状态的索引
void Clear(); //清空表结构和表数据
const bool empty() const; //行数为0则返回true
void connect(const QString &connectionName = QString()); //dt优先连接ds连接的数据库若ds未连接则与内存数据库连接
bool table_to_db(); //将datatable数据全转移到_table_model里并提交到db
/* 将db数据全转移到datatable里使用前必须设置数据库连接(可手动设置或者加入已连接的ds来设置)和tablename
dt.Select("column1='row81'"); int和long不需
eg:DataSet ds_tmp;ds_tmp.connect("myRefDb.db"); DataTable* td_tmp = new DataTable("Damage_Element");ds_tmp.Add(&td_tmp);td_tmp.db_to_table("ShipID = 1"); */
void db_to_table(const QString& sql_filter_exp = "");
void print_table();
void print_model();
const int Length() const;
private:
void _init();
QString _get_conn_name();
void _row_to_model();
DataTable _query_to_table(QSqlQueryModel* query_model); //将数据从querytable转移到table
void _db_to_model(const QString& sql_filter_exp = "");
void _model_to_table();
void _set_dataset(DataSet* ds); //设置此表所属的 DataSet。用户只可通过Add设置此表所属的 DataSet。此接口提供给数据集拷贝使用
private:
QString m_sql_filter_exp = "";
QString _table_name; //加入同一ds的table不可重名。拷贝时拷贝name
DataColumnCollection* _dc_collect = nullptr; /* 只存放列名,标题,也可理解为第-1行的所有数据 */
DataRowCollection* _dr_collect = nullptr; /* 存数据,每一行和每一格 */
DataSet* _data_set = nullptr; //拷贝时忽略该项
QSqlDatabase _db; //拷贝时忽略该项
QSqlTableModel* _table_model = nullptr; //拷贝时忽略该项
};
#endif