C#自定义特性-SQL

语法

原则

自定义特性必须继承自System.Attribute类;

AttributeUsage属性来指定特性的使用范围和是否允许重复等;

在特性类中定义属性,这些属性将用于存储特性值。

示例

cs 复制代码
using System;

// 定义一个自定义特性类
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class CustomAttribute : Attribute
{
    // 特性属性
    public string Description { get; set; }
    public int Version { get; set; }

    // 特性构造函数
    public CustomAttribute(string description, int version)
    {
        Description = description;
        Version = version;
    }
}

// 使用自定义特性
[Custom("This is a sample class", 1)]
public class SampleClass
{
    [Custom("This is a sample method", 1)]
    public void SampleMethod()
    {
        // 方法实现
    }
}

class Program
{
    static void Main()
    {
        // 获取SampleClass类的特性信息
        var classAttributes = typeof(SampleClass).GetCustomAttributes(typeof(CustomAttribute), false);
        foreach (CustomAttribute attr in classAttributes)
        {
            Console.WriteLine($"Class Description: {attr.Description}, Version: {attr.Version}");
        }

        // 获取SampleMethod方法的特性信息
        var methodAttributes = typeof(SampleClass).GetMethod("SampleMethod").GetCustomAttributes(typeof(CustomAttribute), false);
        foreach (CustomAttribute attr in methodAttributes)
        {
            Console.WriteLine($"Method Description: {attr.Description}, Version: {attr.Version}");
        }
    }
}

AttributeUsage中的AllowMultiple属性默认值为false,它决定同种特性类型的实例能否在同一个目标上多次使用,比如在类中的同一个属性上。

特性声明代码

cs 复制代码
using System;
using System.Reflection;

namespace Model.Common
{
    /// <summary>
    /// 用于生成SQLServer数据库查询的like条件
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class SqlLikeAttribute : Attribute
    {
        /// <summary>
        /// 数据库字段名
        /// </summary>
        public string FieldName { get; set; }
        public SqlLikeAttribute(string fidleName)
        {
            FieldName = fidleName;
        }
    }

    /// <summary>
    /// 用于生成SQLServer数据库查询的>、>=、<、<==、=条件
    /// </summary>
    [AttributeUsage(AttributeTargets.Property,AllowMultiple = false)]
    public class SqlRangeAttribute: Attribute
    {
        /// <summary>
        /// 数据库字段名
        /// </summary>
        public string FieldName { get; set; }
        /// <summary>
        /// 取值范围:>、>=、<、<==、=
        /// </summary>
        public string Range { get; set; }
        public SqlRangeAttribute(string fidleName, string range)
        {
            FieldName = fidleName;
            Range= range;
        }
    }

    /// <summary>
    /// 用于生成SQLServer数据库查询的between条件
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class SqlBetweenAttribute : Attribute
    {
        /// <summary>
        /// 数据库字段名
        /// </summary>
        public string FieldName { get; set; }
        /// <summary>
        /// 查询条件实体中的另一个字段名
        /// </summary>
        public string AnotherFieldName { get; set; }
        /// <summary>
        /// 是否是开始
        /// </summary>
        public bool IsStart { get; set; }
        public Object Value { get; set; }
        public SqlBetweenAttribute(string fidleName, string anotherFieldName, bool start = true)
        {
            FieldName = fidleName;
            AnotherFieldName = anotherFieldName;
            IsStart = start;
        }
    }

    /// <summary>
    /// 用于生成SQLServer数据库查询的条件,有SqlIgnoreAttribute修饰的属性直接忽略掉
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class SqlIgnoreAttribute : Attribute
    {
    }

    /// <summary>
    /// 测试
    /// </summary>
    public class AttributeTest
    {
        public static void Test()
        {
            TestModel testModel = new TestModel()
            {
                ID = 1,
                Name = "test",
                Begin = DateTime.Now,
                End = DateTime.Now.AddDays(1),
            };
            Type type = testModel.GetType();
            PropertyInfo[] infos = type.GetProperties();
            foreach (PropertyInfo info in infos)
            {
                SqlBetweenAttribute attr = (SqlBetweenAttribute)info.GetCustomAttribute(typeof(SqlBetweenAttribute), false);
                if (attr != null)
                {
                    string field = attr.FieldName;
                }
            }
        }
    }

    public class TestModel
    {
        public int ID { get; set; }
        public string Name { get; set; }
        [SqlBetween("field", "End")]
        public DateTime Begin { get; set; }
        [SqlBetween("field", "Begin", false)]
        public DateTime End { get; set; }
    }
}

使用特性

cs 复制代码
        /// <summary>
        /// 从实体中获取属性值不为空的属性和值,用于数据库Select的Where条件
        /// 暂时只支持,int、string、double、DateTime
        /// 要求数值类型默认为-1
        /// </summary>
        /// <param name="data"></param>
        /// <param name="prefix">前缀</param>
        /// <returns></returns>
        public static List<string> GetPropertyValueNotNullForSelectWhere(this object data, string prefix)
        {
            string item = "";
            List<string> items = new List<string>();
            Dictionary<string, SqlBetweenAttribute> dic = new Dictionary<string, SqlBetweenAttribute>();
            DateTime dateTime = new DateTime(1, 1, 1, 0, 0, 0);

            PropertyInfo[] propertyInfos = data.GetType().GetProperties();
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                if (propertyInfo.Name.ToUpper() == "ID")
                    continue;

                item = "";
                object obj = propertyInfo.GetValue(data, null);
                switch (propertyInfo.PropertyType.FullName)
                {
                    case "System.Int32":
                        if (Convert.ToInt32(obj) == -1)
                            continue;
                        item = $" and {prefix}{propertyInfo.Name}={Convert.ToInt32(obj)}";
                        break;
                    case "System.String":
                        if (Convert.ToString(obj) == "")
                            continue;
                        item = $" and {prefix}{propertyInfo.Name}='{Convert.ToString(obj)}'";
                        break;
                    case "System.Double":
                        if (Convert.ToDouble(obj) == -1)
                            continue;
                        item = $" and {prefix}{propertyInfo.Name}={Convert.ToDouble(obj)}";
                        break;
                    case "System.Decimal":
                        if (Convert.ToDecimal(obj) == -1)
                            continue;
                        item = $" and {prefix}{propertyInfo.Name}={Convert.ToDecimal(obj)}";
                        break;
                    case "System.DateTime":
                        obj = propertyInfo.GetValue(data, null);
                        if (Convert.ToDateTime(obj) == dateTime)
                            continue;
                        item = $" and {prefix}{propertyInfo.Name}='{Convert.ToDateTime(obj)}'";
                        break;
                }

                //if(!CheckAttrSqlBetween(propertyInfo, obj, ref dic, ref item))
                //    continue;

                CheckAttrSqlRange(propertyInfo, obj, ref item, prefix);
                CheckAttrSqlLike(propertyInfo, obj, ref item, prefix);
                if (!CheckAttrSqlIgnore(propertyInfo, obj, ref item))
                    continue;

                items.Add(item);
            }
            return items;
        }

        /// <summary>
        /// 检查属性是否被SqlBetween特性修饰,并处理
        /// </summary>
        /// <param name="propertyInfo">实体的属性对象</param>
        /// <param name="obj">属性的值</param>
        /// <param name="dic">暂存特性的字典</param>
        /// <param name="item"></param>
        /// <returns>true 表示需要把item加到List<string>中</returns>
        static bool CheckAttrSqlBetween(PropertyInfo propertyInfo, object obj, ref Dictionary<string, SqlBetweenAttribute> dic, ref string item)
        {
            SqlBetweenAttribute attr = (SqlBetweenAttribute)propertyInfo.GetCustomAttribute(typeof(SqlBetweenAttribute), false);
            if (attr == null)
                return true;

            attr.Value = obj;
            if (!dic.ContainsKey(attr.AnotherFieldName))
            {   //缺少另外一个,先缓存
                dic.Add(attr.AnotherFieldName, attr);
                return false;
            }
            else
            {
                SqlBetweenAttribute _attr = dic[attr.AnotherFieldName];
                dic.Remove(attr.AnotherFieldName);

                SqlBetweenAttribute attrb = attr.IsStart ? attr : _attr;
                SqlBetweenAttribute attre = attr.IsStart ? _attr : attr;
                switch (propertyInfo.PropertyType.FullName)
                {
                    case "System.Int32":
                    case "System.Double":
                    case "System.Decimal":
                        item = $" and {attr.FieldName} between {attrb.Value} and {attre.Value}";
                        break;
                    case "System.String":
                    case "System.DateTime":
                        item = $" and {attr.FieldName} between '{attrb.Value}' and '{attre.Value}'";
                        break;
                }
                return true;
            }
        }

        /// <summary>
        /// 检查属性是否被SqlRange特性修饰,并处理
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <param name="obj"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        static void CheckAttrSqlRange(PropertyInfo propertyInfo, object obj, ref string item, string prefix)
        {
            SqlRangeAttribute attr = (SqlRangeAttribute)propertyInfo.GetCustomAttribute(typeof(SqlRangeAttribute), false);
            if (attr == null)
                return;

            switch (propertyInfo.PropertyType.FullName)
            {
                case "System.Int32":
                case "System.Double":
                case "System.Decimal":
                    item = $" and {prefix}{attr.FieldName} {attr.Range} {obj} ";
                    break;
                case "System.String":
                case "System.DateTime":
                    item = $" and {prefix}{attr.FieldName} {attr.Range} '{obj}' ";
                    break;
            }
            return;
        }

        /// <summary>
        /// 检查属性是否被SqlLike特性修饰,并处理
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <param name="obj"></param>
        /// <param name="item"></param>
        static void CheckAttrSqlLike(PropertyInfo propertyInfo, object obj, ref string item, string prefix)
        {
            SqlLikeAttribute attr = (SqlLikeAttribute)propertyInfo.GetCustomAttribute(typeof(SqlLikeAttribute), false);
            if (attr == null)
                return;

            switch (propertyInfo.PropertyType.FullName)
            {
                case "System.String":
                    item = $" and ({prefix}{attr.FieldName} like '%{obj}%' or {prefix}{attr.FieldName}='{obj}') ";
                    break;
            }
            return;
        }

        /// <summary>
        /// 检查属性是否被SqlIgnoreAttribute特性修饰,如果修饰则不加入到Where条件中
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <param name="obj"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        static bool CheckAttrSqlIgnore(PropertyInfo propertyInfo, object obj, ref string item)
        {
            SqlIgnoreAttribute attr = (SqlIgnoreAttribute)propertyInfo.GetCustomAttribute(typeof(SqlIgnoreAttribute), false);
            if (attr == null)
                return true;
            else
                return false;
        }
相关推荐
xmjd msup19 分钟前
mysql的分区表
数据库·mysql
Lyyaoo.19 分钟前
【JAVA Spring面经】Spring 事务失效情况
java·数据库·spring
MeAT ITEM24 分钟前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
dovens28 分钟前
PostgreSQL 中进行数据导入和导出
大数据·数据库·postgresql
IOT.FIVE.NO.128 分钟前
claude code desktop cowork报错解决和记录Workspace..The isolated Linux environment ...
linux·服务器·数据库
Rick199337 分钟前
mysql 慢查询怎么快速定位
android·数据库·mysql
科技小花8 小时前
全球化深水区,数据治理成为企业出海 “核心竞争力”
大数据·数据库·人工智能·数据治理·数据中台·全球化
X56619 小时前
如何在 Laravel 中正确保存嵌套动态表单数据(主服务与子服务)
jvm·数据库·python
虹科网络安全10 小时前
艾体宝干货|数据复制详解:类型、原理与适用场景
java·开发语言·数据库
2301_7717172110 小时前
解决mysql报错:1406, Data too long for column
android·数据库·mysql