C#自定义特性-SQL

语法

原则

        自定义特性必须继承自System.Attribute类;
        AttributeUsage属性来指定特性的使用范围和是否允许重复等;
        在特性类中定义属性,这些属性将用于存储特性值。

示例

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,它决定同种特性类型的实例能否在同一个目标上多次使用,比如在类中的同一个属性上。 

特性声明代码

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; }
    }
}

使用特性


        /// <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;
        }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/914754.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

彻底解决单片机BootLoader升级程序失败问题

文章目录 1、引言2、MicroBoot&#xff1a;优雅的解决升级问题问题1&#xff1a;bootloader 在跳转到app前没有清理干净存在的痕迹问题2&#xff1a; 需要 APP 传递信息给 Bootloader问题3&#xff1a; APP单独运行没有问题&#xff0c;通过Bootloader跳转到APP运行莫名死机问题…

v-html 富文本中图片使用element-ui image-viewer组件实现预览,并且阻止滚动条

效果 导入组件 import ElImageViewer from "element-ui/packages/image/src/image-viewer"; components:{ ElImageViewer },模板使用组件 <el-image-viewerv-if"isShowPics":on-close"closeViewer":url-list"srcList"/>定义两…

山寨一个Catch2的SECTION

Catch2 是一个 C 单元测试库&#xff0c;吹嘘自己比 NUnit 和 xUnit 还要高明&#xff0c; 支持在 TEST_CASE() 中的多个 SECTION&#xff0c; 意思是说 SECTION 外头的代码相当于setup 和 teardown&#xff0c;section 内部则被认为是实际的 test case&#xff0c; 这种写法可…

深入剖析【C++继承】:单一继承与多重继承的策略与实践,解锁代码复用和多态的编程精髓,迈向高级C++编程之旅

​​​​​​​ &#x1f31f;个人主页&#xff1a;落叶 &#x1f31f;当前专栏: C专栏 目录 继承的概念及定义 继承的概念 继承定义 定义格式 继承基类成员访问⽅式的变化 继承类模板 基类和派⽣类间的转换 继承中的作⽤域 隐藏规则 成员函数的隐藏 考察继承【作⽤…

36.Redis核心设计原理

本文针对前面的讲解做一次总结 1.Redis基本特性 1.非关系型的键值对数据库&#xff0c;可以根据键以O(1)的时间复杂度取出或插入关联值 2.Redis的数据是存在内存中的 3.键值对中键的类型可以是字符串&#xff0c;整型&#xff0c;浮点型等&#xff0c;且键是唯一的 4.键值对中…

项目模块十七:HttpServer模块

一、项目模块设计思路 目的&#xff1a;实现HTTP服务器搭建 思想&#xff1a;设计请求路由表&#xff0c;记录请求方法与对应业务的处理函数映射关系。用户实现请求方法和处理函数添加到路由表&#xff0c;服务器只接受请求并调用用户的处理函数即可。 处理流程&#xff1a; …

vue项目npm run serve出现【- Network: unavailable】(从排查到放弃)

1. 问题现象 环境&#xff1a; 系统&#xff1a;win11node&#xff1a;v16.20.2“vue”: “2.6.10” 执行npm run serve启动vue项目&#xff0c;期望&#xff1a; App running at:- Local: http://localhost:9528/ - Network: http://x.x.x.x:9528/实际&#xff1a; App runn…

喜报|超维机器人荣获昇腾AI创新大赛铜奖

近日&#xff0c;在备受瞩目的昇腾AI创新大赛中&#xff0c;超维机器人凭借扎实的技术实力和创新产品&#xff0c;荣获大赛铜奖。这一荣誉不仅展现了超维机器人在智能巡检领域的技术创新与突破&#xff0c;也标志着超维机器人的智能巡检解决方案在人工智能领域获得了广泛认可&a…

编程初学者的第一个 Rust 系统

编程初学者的第一个 Rust 系统 对编程初学者而言&#xff0c;存在一个 “第一个系统” 的问题&#xff0c;如果没有学会第一个系统&#xff0c;编程初学者是学不会编程的。原因是&#xff0c;现实生活里的应用程序都是有一定体量的&#xff0c;不是几十行&#xff0c;几百行的…

单元测试、集成测试、系统测试有什么区别

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 单元测试、集成测试、系统测试有什么区别 1、粒度不同 集成测试bai粒度居中&#xff0c;单元测试粒度最小&#xff0c;系统du测试粒度最大。 2、测试方式不同…

Java面试要点16 - 面向对象基础:类与对象

本文目录 一、引言二、类的定义与对象创建三、成员变量与封装四、构造方法五、this关键字六、静态成员七、总结 一、引言 面向对象编程是Java的核心特性之一&#xff0c;它通过类和对象的概念来组织和管理代码&#xff0c;使代码更加模块化、可复用和易于维护。本文将深入探讨…

【免越狱】iOS砸壳 可下载AppStore任意版本 旧版本IPA下载

软件介绍 下载iOS旧版应用&#xff0c;简化繁琐的抓包流程。 一键生成去更新IPA&#xff08;手机安装后&#xff0c;去除App Store的更新检测&#xff09;。 软件界面 支持系统 Windows 10/Windows 8/Windows 7&#xff08;由于使用了Fiddler库&#xff0c;因此需要.Net环境…

LeetCode 热题100 之 多维动态规划

1.不同路径 思路分析&#xff1a;动规五部曲 dp数组定义&#xff1a;dp[i][j]表示从起点&#xff08;0&#xff0c;0&#xff09;到位置(i,j)的路径数量递推公式&#xff1a;dp[i][j] dp[i-1][j] dp[i][j-1] 从 (i-1, j) 位置到 (i, j) 需要走一步向下的路径。从 (i, j-1) 位…

文件操作(3)

前言&#xff0c;在上篇博客介绍了如何正确的打开一个文件和关闭一个文件&#xff0c;今天我们来学习如何在文件中输出和输入数据。 对文件数据的读写可以分为顺序读写和随机读写。顺序读写&#xff0c;即挨着顺序对文件中的数据进行输入或输出。 在这片博客中&#xff0c;我们…

Openstack7--安装消息队列服务RabbitMQ

只需要在控制节点安装 安装RabbitMQ yum -y install rabbitmq-server 启动RabbitMQ并设置开机自启 systemctl start rabbitmq-server;systemctl enable rabbitmq-server 创建 rabbitmq 用户 并设置密码为 000000 rabbitmqctl add_user rabbitmq 000000 如果你不慎创错了…

Unity图形学之Shader2.0 模板测试

1.模版测试&#xff1a;符合条件的 通过 不符合条件的 像素 丢弃 比较公式&#xff1a; if&#xff08;&#xff08;referenceValue&readMask&#xff09; comparisonFunction &#xff08;stencilBufferValue&readMask&#xff09;&#xff09; 通过像素 else 抛弃…

020_Servlet_Mysql学生选课系统(新版)_lwplus87

摘 要 随着在校大学生人数的不断增加&#xff0c;教务系统的数据量也不断的上涨。针对学生选课这一环节&#xff0c;本系统从学生网上自主选课以及课程发布两个大方面进行了设计&#xff0c;基本实现了学生的在线信息查询、选课功能以及教师对课程信息发布的管理等功能&…

SpringBoot教程(二十五) | SpringBoot配置多个数据源

SpringBoot教程&#xff08;二十五&#xff09; | SpringBoot配置多个数据源 前言方式一&#xff1a;使用dynamic-datasource-spring-boot-starter引入maven依赖配置数据源动态切换数据源实战 方式二&#xff1a;使用AbstractRoutingDataSource1. 创建数据源枚举类2. 创建数据源…

Python 正则表达式进阶用法:分组与引用详解

Python 正则表达式进阶用法&#xff1a;分组与引用详解 正则表达式是一种用于字符串匹配和处理的强大工具。它不仅能识别简单的文本模式&#xff0c;还能通过更高级的特性来完成复杂的文本处理任务。本文将深入探讨 Python 正则表达式中的“分组”和“引用”——两个在高级匹配…

米家通过HomeAssistant控制笔记本电脑开关机

米家通过HomeAssistant控制笔记本电脑开关机 配置HomeAssistant配置EMQX mqtt自动化配置电脑关机实现电脑开机实现&#xff08;网络唤醒WOL包&#xff09; 环境准备&#xff1a; HomeAssistant&#xff1a;能配置接入米家的设备&#xff0c;我这里采用fnos安装MQTT服务器&…