zoukankan      html  css  js  c++  java
  • 转:C#制作ORM映射学习笔记一 自定义Attribute类

    之前在做unity项目时发现只能用odbc连接数据库,感觉非常的麻烦,因为之前做web开发的时候用惯了ORM映射,所以我想在unity中也用一下ORM(虽然我知道出于性能的考虑这样做事不好的,不过自己的小项目吗管他的,自己爽就行了)。不过现在世面上的ORM映射基本都是为web项目设计的,与unity项目很难契合,所以我决定自己做一个简易的ORM映射。虽然想的很美但是实际做起来才发现还是挺复杂的,所以我在这里记录一下这次的开发过程,防止以后遗忘。

    今天先记录一下如何通过自定义attribute类实现对类名、属性名和关系数据库中的表名、字段名等信息映射。关于attribute类网上资料很多,这里不详细介绍了,下面具体代码中用到的地方会有具体说明。

    首先需要自定义三个attribute类,分别是TableAttribute、ColumnAttribute和PrimaryKeyAttribute,这三个类将分别描述表名、字段名和主键名。下面是具体的实现。

    1.TableAttribute

    using System;  
      
    namespace ORM  
    {  
        [AttributeUsage(AttributeTargets.Class)]  
        public class TableAttribute : Attribute  
        {  
            public TableAttribute(string tableName)  
            {  
                this.Value = tableName;  
            }  
      
            public string Value { get; protected set; }  
        }  
    }  

    2.ColumnAttribute

    using System;  
      
    namespace ORM  
    {  
        [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]  
        public class ColumnAttribute : Attribute  
        {  
            public ColumnAttribute(string columnName)  
            {  
                this.Value = columnName;  
            }  
      
            public string Value { get; protected set; }  
        }  
    }  

    3.PrimaryKeyAttribute

    using System;  
      
    namespace ORM  
    {  
        [AttributeUsage(AttributeTargets.Class)]  
        public class PrimaryKeyAttribute : Attribute  
        {  
            public PrimaryKeyAttribute(string primaryKey)  
            {  
                this.Value = primaryKey;  
            }  
      
            public string Value { get; protected set; }  
            public bool autoIncrement = false;  
      
        }  
    }  

    这里要注意的地方不多,主要有以下几点:

    1.AttributeTargets是用来表名attribute类应该在何种程序实体前放置,class表示应该在类声明前放置,Field表示可以在字段前放置,Property表示可以在属性前放置。

    2.AllowMultiple表示同一个程序体前能否放置多个相同的该自定义attribute类,这里我设为false,因为一个属性在数据表中只能对应一个字段。

    3.Inherited表示在描述类属性时,这个attribute能否被子类继承,这里我也设为了false,因为orm映射的类不会涉及到继承的问题。

    4.自定义的attribute在定义是类名都是以attribute结尾的,但是在使用时不需要将attribute也打出来,下面我举个例子来说明。我用sqlite定义了一个userinfo表(为什么是用sqlite原因很简单,因为sqlite比较简单粗暴),表结构如下。

    这张表对应的类声明如下:

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using System.Threading.Tasks;  
      
    namespace ORM  
    {  
        [Table("userinfo")]  
        [PrimaryKey("Id", autoIncrement = true)]  
        public class User  
        {  
      
            [Column("Id")]  
            public int Id { get; set; }  
      
            [Column("UserName")]  
            public string UserName { get; set; }  
      
            [Column("Password")]  
            public string Password { get; set; }  
      
            [Column("CreateTime")]  
            public DateTime CreateTime { get; set; }  
      
            [Column("Status")]  
            public bool Status { get; set; }  
      
            [Column("RoleType")]  
            public RoleType RoleType { get; set; }  
      
        }  
      
        public enum RoleType : int  
        {  
            Common = 1,  
            Admin = 2  
        }  
    }  

    为了在后面实现数据库访问,包括增删改查操作时更加的方便,我们在做一个帮助类AttributeProcess,这个类是一个静态类,里面的方法也是静态方法。设计这个类的目的是提供一个公共的方法来提取类所对应的表名、字段名、主键名的属性。代码如下:

    using System;  
    using System.Collections;  
    using System.Collections.Generic;  
    using System.Text;  
    using System.Reflection;  
      
    namespace ORM  
    {  
        public static class AttributeProcess  
        {  
      
            /// <summary>  
            /// 获取表名  
            /// </summary>  
            /// <param name="type"></param>  
            /// <returns></returns>  
            public static string GetTableName(Type type)  
            {  
                string tableName = string.Empty;  
                object[] attributes = type.GetCustomAttributes(false);  
                foreach (var attr in attributes)  
                {  
                    if (attr is TableAttribute)  
                    {  
                        TableAttribute tableAttribute = attr as TableAttribute;  
                        tableName = tableAttribute.Value;  
                    }  
                }  
                if (string.IsNullOrEmpty(tableName))  
                {  
                    tableName = type.Name;  
                }  
                return tableName;  
            }  
      
            /// <summary>  
            /// 获取字段名  
            /// </summary>  
            /// <param name="property"></param>  
            /// <returns></returns>  
            public static string GetColumnName(PropertyInfo property)  
            {  
                string columnName = string.Empty;  
                object[] attributes = property.GetCustomAttributes(false);  
                foreach (var attr in attributes)  
                {  
                    if (attr is ColumnAttribute)  
                    {  
                        ColumnAttribute columnAttr = attr as ColumnAttribute;  
                        columnName = columnAttr.Value;  
                    }  
                }  
                if (string.IsNullOrEmpty(columnName))  
                {  
                    columnName = property.Name;  
                }  
                return columnName;  
            }  
      
            /// <summary>  
            /// 判断主键是否自增  
            /// </summary>  
            /// <param name="property"></param>  
            /// <returns></returns>  
            public static bool IsIncrement(Type type)  
            {  
                object[] attributes = type.GetCustomAttributes(false);  
                foreach (var attr in attributes)  
                {  
                    if (attr is PrimaryKeyAttribute)  
                    {  
                        PrimaryKeyAttribute primaryKeyAttr = attr as PrimaryKeyAttribute;  
                        return primaryKeyAttr.autoIncrement;  
                    }  
                }  
                return false;  
            }  
      
            /// <summary>  
            /// 获取主键名  
            /// </summary>  
            /// <param name="type"></param>  
            /// <returns></returns>  
            public static string GetPrimary(Type type)  
            {  
                object[] attributes = type.GetCustomAttributes(false);  
                foreach (var attr in attributes)  
                {  
                    if (attr is PrimaryKeyAttribute)  
                    {  
                        PrimaryKeyAttribute primaryKeyAttr = attr as PrimaryKeyAttribute;  
                        return primaryKeyAttr.Value;  
                    }  
                }  
                return null;  
            }  
      
            /// <summary>  
            /// 判断属性是否为主键  
            /// </summary>  
            /// <param name="type"></param>  
            /// <param name="property"></param>  
            /// <returns></returns>  
            public static bool IsPrimary(Type type, PropertyInfo property)  
            {  
                string primaryKeyName = GetPrimary(type);  
                string columnName = GetColumnName(property);  
                return (primaryKeyName == columnName);  
            }  
      
        }  
    }  

    其中获取自定义attribute和其中的属性值的方法不难,主要就是先通过GetCustomAttributes方法来获取程序体前放置的所有的自定义attribute,然后循环遍历找到需要的attribute并读取需要的属性值,这样就可以获取到需要的数据库相关信息了。另外,为了方便起见,在获取表名和字段名时,如果没有在类名或者属性名前放置TableAttribute类或者ColumnAttribute类,那么将自动的读取类名或者属性名做为表名和字段名返回。下面做一个简单的测试,将user类对应的表名和其中属性对应的字段名都打印出来,测试代码如下:

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using System.Reflection;  
      
    namespace ORM  
    {  
        class Program  
        {  
            static void Main(string[] args)  
            {  
                Type type = typeof(User);  
                PropertyInfo[] properties = type.GetProperties();  
                Console.WriteLine(AttributeProcess.GetTableName(type));  
                foreach (var item in properties)  
                {  
                    Console.WriteLine(AttributeProcess.GetColumnName(item));  
                }  
            }  
        }  
    }  

    注:GetProperties方法是Type类下的一个方法,用来获取类中的所有属性的信息。

    测试结果如下:

    好了,到这里自定义Attribute类的工作就基本完成了,下面就要正式开始正式的数据库操作了,我会在后续的文章中进行说明,今天就先到这里。

  • 相关阅读:
    2019-9-2-win10-uwp-判断本地ip
    2018-8-10-使用-Resharper-特性
    2018-8-10-WPF-checkbox文字下掉
    2018-8-10-调试-ms-源代码
    2018-8-10-cant-found-Microsoft.VSSDK.BuildTools.15.0.26201
    2019-9-18-WPF-如何调试-binding
    2018-8-10-WPF-控件继承树
    2018-8-10-sublime-Text-正则替换
    植物大战僵尸阳光冷却地址
    cs1.6 人物地址查询
  • 原文地址:https://www.cnblogs.com/vaevvaev/p/7054921.html
Copyright © 2011-2022 走看看