From 34d1af459ece034be2cc8187e5d8a5e7d863cbfb Mon Sep 17 00:00:00 2001 From: Elivo Date: Mon, 27 Oct 2025 13:56:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20IndexAttribute=EF=BC=8C?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E6=A0=87=E8=AE=B0=E7=B4=A2=E5=BC=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Apewer/Source/ColumnAttribute.cs | 17 +++++-- Apewer/Source/IndexAttribute.cs | 81 ++++++++++++++++++++++++++++++++ Apewer/Source/Order.cs | 16 +++++++ Apewer/Source/TableIndex.cs | 44 +++++++++++++++++ Apewer/Source/TableStructure.cs | 38 +++++++++++++-- 5 files changed, 189 insertions(+), 7 deletions(-) create mode 100644 Apewer/Source/IndexAttribute.cs create mode 100644 Apewer/Source/Order.cs create mode 100644 Apewer/Source/TableIndex.cs diff --git a/Apewer/Source/ColumnAttribute.cs b/Apewer/Source/ColumnAttribute.cs index fa9308c..a10604b 100644 --- a/Apewer/Source/ColumnAttribute.cs +++ b/Apewer/Source/ColumnAttribute.cs @@ -1,8 +1,6 @@ -using Apewer.Internals; -using System; +using System; using System.Collections.Generic; using System.Reflection; -using System.Text; namespace Apewer.Source { @@ -28,6 +26,8 @@ namespace Apewer.Source private bool _valid = true; private bool _nullable = false; + private List _indexes = new List(); + private void Init(string field, ColumnType type, int length) { _field = field; @@ -65,6 +65,9 @@ namespace Apewer.Source /// 字段类型。 public ColumnType Type { get => _type; } + /// 字段上的索引。 + public IndexAttribute[] Indexes { get => _indexes.ToArray(); } + #region 附加 /// 此特性有效。 @@ -153,6 +156,14 @@ namespace Apewer.Source } if (!ca._primarykey && RuntimeUtility.Contains(property)) ca._primarykey = true; + // 获取索引。 + var indexes = IndexAttribute.Parse(property); + foreach (var index in indexes) + { + index.SetColumn(ca); + } + ca._indexes.AddRange(indexes); + // 检查免更新特性。 var nu = RuntimeUtility.GetAttribute(property, false); if (nu) ca._noupdate = true; diff --git a/Apewer/Source/IndexAttribute.cs b/Apewer/Source/IndexAttribute.cs new file mode 100644 index 0000000..49fa0ac --- /dev/null +++ b/Apewer/Source/IndexAttribute.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Apewer.Source +{ + + /// 索引。 + [Serializable] + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)] + public sealed class IndexAttribute : Attribute, IToJson + { + + PropertyInfo _property = null; + ColumnAttribute _column; + + string _name = null; + Order _order = Order.Ascend; + + /// 索引名称。 + public string Name { get => _name; } + + /// 排序。 + public Order Order { get => _order; set => _order = value; } + + /// 列。 + public ColumnAttribute Column { get => _column; } + + /// 属性。 + public PropertyInfo Property { get => _property; } + + /// 表示此属性是索引的一部分。 + /// 索引名称。 + public IndexAttribute(string name) + { + if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); + _name = name; + } + + internal void SetColumn(ColumnAttribute column) + { + _column = column; + } + + /// 解析列的索引。 + /// 注意:此方法不再抛出异常,当不存在正确的列特性时将返回 NULL 值 + public static IndexAttribute[] Parse(PropertyInfo property) + { + if (property == null) return null; + + var attributes = property.GetCustomAttributes(typeof(IndexAttribute), true); + var ias = new List(); + foreach (var attribute in attributes) + { + var ia = attribute as IndexAttribute; + if (ia == null) continue; + if (ia._name.IsEmpty()) continue; + + ia._property = property; + ias.Add(ia); + } + return ias.ToArray(); + } + + /// 生成 Json 对象。 + /// + public Json ToJson() + { + var json = Json.NewObject(); + json.SetProperty("name", _name); + json.SetProperty("order", _order.ToString()); + if (_column != null) json.SetProperty("column", _column.ToJson()); + return json; + } + + /// + public override string ToString() => $"Index = {_name}, Field = {_column?.Field}, Order = {_order}"; + + } + +} diff --git a/Apewer/Source/Order.cs b/Apewer/Source/Order.cs new file mode 100644 index 0000000..7ecbe47 --- /dev/null +++ b/Apewer/Source/Order.cs @@ -0,0 +1,16 @@ +namespace Apewer.Source +{ + + /// 排序。 + public enum Order + { + + /// 升序排序。 + Ascend, + + /// 降序排序。 + Descend + + } + +} diff --git a/Apewer/Source/TableIndex.cs b/Apewer/Source/TableIndex.cs new file mode 100644 index 0000000..b973a60 --- /dev/null +++ b/Apewer/Source/TableIndex.cs @@ -0,0 +1,44 @@ +using System; + +namespace Apewer.Source +{ + + /// 索引。 + public sealed class TableIndex + { + + /// 索引名称。 + public string Name { get; } + + /// 表。 + public TableAttribute Table { get; } + + /// 索引字段。 + public IndexAttribute[] Fields { get; } + + /// 创建索引实例。 + /// + internal TableIndex(string name, TableAttribute table, IndexAttribute[] fields) + { + if (name.IsEmpty()) throw new ArgumentNullException(nameof(name)); + if (table == null) throw new ArgumentNullException(nameof(table)); + if (fields == null) throw new ArgumentNullException(nameof(fields)); + + Name = name; + Table = table; + Fields = fields; + } + + /// + public override string ToString() + { + var fields = Fields.FindAll(x => x != null && x.Column != null); + if (fields.IsEmpty()) return Name; + + var array = fields.Map(x => x.Order == Order.Ascend ? x.Column.Field : $"{x.Column.Field} DESC"); + return $"{Name} ({array.Join(", ")})"; + } + + } + +} diff --git a/Apewer/Source/TableStructure.cs b/Apewer/Source/TableStructure.cs index 5e6797d..0f970a9 100644 --- a/Apewer/Source/TableStructure.cs +++ b/Apewer/Source/TableStructure.cs @@ -1,10 +1,7 @@ -using Apewer.Internals; -using Apewer; -using System; +using System; using System.Collections.Generic; using System.Data; using System.Reflection; -using System.Text; namespace Apewer.Source { @@ -20,6 +17,7 @@ namespace Apewer.Source TableAttribute _table = null; ColumnAttribute _key = null; ColumnAttribute _flag = null; + TableIndex[] _indexes = null; ColumnAttribute[] _columns = null; ColumnAttribute[] _fillable = null; @@ -31,6 +29,9 @@ namespace Apewer.Source /// 表特性。 public TableAttribute Table { get => _table; } + /// 索引。 + public TableIndex[] Indexes { get => _indexes; } + /// 列信息。 public ColumnAttribute[] Columns { get => _columns; } @@ -120,6 +121,7 @@ namespace Apewer.Source var columns = new ColumnAttribute[total]; var columnsCount = 0; var fillable = new List(total); + var indexesDict = new Dictionary>(); if (total > 0) { var caForce = force || (ta ? ta.AllProperties : false); @@ -151,6 +153,24 @@ namespace Apewer.Source } } + // 索引 + foreach (var index in ca.Indexes) + { + var indexName = index.Name.Lower(); + if (indexName.IsEmpty()) continue; + + if (indexesDict.TryGetValue(indexName, out var list)) + { + list.Add(index); + } + else + { + list = new List(); + list.Add(index); + indexesDict.Add(indexName, list); + } + } + // 可查询的列。 fillable.Add(ca); continue; @@ -166,6 +186,15 @@ namespace Apewer.Source } if (columnsCount > 0 && columnsCount != columns.Length) columns = columns.Slice(0, columnsCount); + // 整理索引。 + var indexes = new List(); + foreach (var indexesList in indexesDict.Values) + { + var indexName = indexesList[0].Name; + var tableIndex = new TableIndex(indexName, ta, indexesList.ToArray()); + indexes.Add(tableIndex); + } + // 排序,将 Key 和 Flag 排在最前。 columns = ColumnAttribute.Sort(columns); @@ -174,6 +203,7 @@ namespace Apewer.Source ts._table = ta; ts._key = key; ts._flag = flag; + ts._indexes = indexes.ToArray(); ts._columns = columns; ts._model = model; ts._fillable = fillable.ToArray();