转: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类的工作就基本完成了,下面就要正式开始正式的数据库操作了,我会在后续的文章中进行说明,今天就先到这里。

时间: 2024-08-03 03:09:18

转:C#制作ORM映射学习笔记一 自定义Attribute类的相关文章

转:C#制作ORM映射学习笔记三 ORM映射实现

现在开始实现ORM的主体模块,首先需要在项目中新建一个类,命名为DbAccess,然后在项目的引用中添加两个dll,分别是MySql.Data.dll和System.Data.SQLite.dll,这两个dll都可以在对应的数据库官网上下载到,为了方便我这里也提供一个下载地址.添加好dll后需要在DbAccess中添加几个名空间,具体代码如下: using System; using System.Collections; using System.Collections.Generic; us

转:C#制作ORM映射学习笔记二 配置类及Sql语句生成类

在正式开始实现ORM之前还有一点准备工作需要完成,第一是实现一个配置类,这个很简单的就是通过静态变量来保存数据库的一些连接信息,等同于.net项目中的web.config的功能:第二需要设计实现一个sql语句的生成类来帮助生成sql语句,当前如果不实现这个类也不会影响orm的制作,之所以要做这么一个类主要有几个目的,1.减少sql语句中拼写错误的发生.2.统一解决防sql注入的问题. 下面分别说明一下这两个类的实现方式: 1.配置类DbConfig using System; using Sys

Sharepoint2013搜索学习笔记之自定义结果显示模板(九)

搜索结果通过套用定义好的显示模板来展示结果,显示模板由js和html组成,我们可以通过修改显示模板,然后将修改好的显示模板跟搜索结果绑定起来,来修改搜索结果的显示效果,例子如下图: 修改前 修改后 第一步,确定显示需要修改的显示模板,打开ie,摁f12,定位到搜索结果列表项找到需要修改的搜索项模板 第二步,从搜索中心进入网站设置页面 第三步,点击web设计器库的母版页和页面布局 第四步,进入母版页样式库的 Display Templates/search目录,该目录就是存放搜索结果显示模板的地方

shiro学习笔记_0600_自定义realm实现授权

博客shiro学习笔记_0400_自定义Realm实现身份认证 介绍了认证,这里介绍授权. 1,仅仅通过配置文件来指定权限不够灵活且不方便.在实际的应用中大多数情况下都是将用户信息,角色信息,权限信息 保存到了数据库中.所以需要从数据库中去获取相关的数据信息.可以使用 shiro 提供的JdbcRealm来实现,,也可以自定义realm来实现.使用jdbcRealm往往也不够灵活.所以在实际应用中大多数情况都是自定义Realm来实现. 2,自定义Realm 需要继承 AuthorizingRea

[转载]SharePoint 2013搜索学习笔记之自定义结果源

搜索中心新建好之后在搜索结果页上会默认有所有内容,人员,对话,视频这四个结果分类,每个分类会返回指定范围的搜索结果,这里我再添加了部门日志结果分类,搜索这个分类只会返回部门日志内容类型的搜索结果,要实现这个效果,步骤如下: 第一步,进入管理中心,进入管理应用程序,点击Search Service 应用程序,进入搜索管理页,再点击结果源如图: 第二步,新建结果源,填写名称,协议填写本地sharepoint,凭据信息选择默认, 第三步,点击启动查询生成器,生成查询语句,最后点保存,接着继续点新建内容

javascript学习笔记---ECMAScriptECMAScript 对象----定义类或对象

使用预定义对象只是面向对象语言的能力的一部分,它真正强大之处在于能够创建自己专用的类和对象. ECMAScript 拥有很多创建对象或类的方法. 原始的方式 因为对象的属性可以在对象创建后动态定义(后绑定),类似下面的代码: var oCar = new Object; oCar.color = "blue"; oCar.doors = 4; oCar.mpg = 25; oCar.showColor = function() { alert(this.color); };不过这里有一

java学习笔记07--日期操作类

java学习笔记07--日期操作类 一.Date类 在java.util包中定义了Date类,Date类本身使用非常简单,直接输出其实例化对象即可. [java] view plaincopy public class T { public static void main(String[] args) { Date date  = new Date(); System.out.println("当前日期:"+date); //当前日期:Thu May 16 23:00:57 CST 

Sharepoint2013搜索学习笔记之自定义结果精简分类(八)

搜索结果页左边的结果精简分类是可以根据搜索结果自定义的,在搜索的部门日志结果集页面上我搜索测试关键字,左边分类导航在默认分类的基础上增加了一个日志类型的分类,如下图: 要实现这个效果,导航到之前定义的depresult.aspx页面上,点编辑页面 Sharepoint2013搜索学习笔记之自定义结果精简分类(八)

Sharepoint2013搜索学习笔记之自定义查询规则(十)

自定义查询规则,可以根据搜索的关键字将指定的一个或一堆搜索结果提升到第一的位置,如我搜索周杰伦,可以指定搜索最靠前的结果是sharepoint网站内周杰伦的视频如下图: 第一步,进入管理中心,点击管理应用程序,点击search service应用程序,进入搜索管理页面,点击查询规则 第二步,选择一个结果源,如sharepoint本地结果,然后点击新建查询规则,填好相应值, 第三步,点添加结果块编辑查询语句,然后保存. Sharepoint2013搜索学习笔记之自定义查询规则(十)