转: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 = ,
Admin =
}
}
为了在后面实现数据库访问,包括增删改查操作时更加的方便,我们在做一个帮助类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类的工作就基本完成了,下面就要正式开始正式的数据库操作了,我会在后续的文章中进行说明,今天就先到这里。
转:C#制作ORM映射学习笔记一 自定义Attribute类的更多相关文章
- 转:C#制作ORM映射学习笔记三 ORM映射实现
现在开始实现ORM的主体模块,首先需要在项目中新建一个类,命名为DbAccess,然后在项目的引用中添加两个dll,分别是MySql.Data.dll和System.Data.SQLite.dll,这 ...
- 转:C#制作ORM映射学习笔记二 配置类及Sql语句生成类
在正式开始实现ORM之前还有一点准备工作需要完成,第一是实现一个配置类,这个很简单的就是通过静态变量来保存数据库的一些连接信息,等同于.net项目中的web.config的功能:第二需要设计实现一个s ...
- EF学习笔记——生成自定义实体类
使用EF,采用DataBase 模式,实体类都是按照数据库的定义自动生成,我们似乎无法干预.如果要生成自定义的实体类,该怎么做呢? 思路是这样的: 1.我们要自定义生成的实体类,都是分部类(parti ...
- PythonI/O进阶学习笔记_4.自定义序列类(序列基类继承关系/可切片对象/推导式)
前言: 本文代码基于python3 Content: 1.python中的序列类分类 2. python序列中abc基类继承关系 3. 由list的extend等方法来看序列类的一些特定方法 4. l ...
- JVM学习笔记-第六章-类文件结构
JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...
- [转载]SharePoint 2013搜索学习笔记之自定义结果源
搜索中心新建好之后在搜索结果页上会默认有所有内容,人员,对话,视频这四个结果分类,每个分类会返回指定范围的搜索结果,这里我再添加了部门日志结果分类,搜索这个分类只会返回部门日志内容类型的搜索结果,要实 ...
- java学习笔记07--日期操作类
java学习笔记07--日期操作类 一.Date类 在java.util包中定义了Date类,Date类本身使用非常简单,直接输出其实例化对象即可. public class T { public ...
- Hadoop学习笔记—5.自定义类型处理手机上网日志
转载自http://www.cnblogs.com/edisonchou/p/4288737.html Hadoop学习笔记—5.自定义类型处理手机上网日志 一.测试数据:手机上网日志 1.1 关于这 ...
- shiro学习笔记_0600_自定义realm实现授权
博客shiro学习笔记_0400_自定义Realm实现身份认证 介绍了认证,这里介绍授权. 1,仅仅通过配置文件来指定权限不够灵活且不方便.在实际的应用中大多数情况下都是将用户信息,角色信息,权限信息 ...
随机推荐
- 15.VUE学习之-表单中使用key唯一令牌解决表单值混乱问题
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...
- ActiveMQ发布-订阅消息模式(同点对点模式的区别)
点对点与发布订阅最初是由JMS定义的.这两种模式主要区别或解决的问题就是发送到队列的消息能否重复消费(多订阅) 点对点: 消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费 ...
- BFS:HDU2597-Dating with girls(2) (分时间标记状态)
Dating with girls(2) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- Go语言之反射(一)
反射 反射是指在程序运行期对程序本身进行访问和修改的能力.程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分.在运行程序时,程序无法获取自身的信息.支持反射的语言可以在程序编译期将 ...
- 一次失败的刷题经历:[LeetCode]292之尼姆游戏(Nim Game)
最近闲来无事刷LeetCode,发现这道题的Accept Rate还是挺高的,尝试着做了一下,结果悲剧了,把过程写下来,希望能长点记性.该题的描述翻译成中文如下: 你正在和你的朋友玩尼姆游戏(Nim ...
- 新博客 http://kunyashaw.com/
感谢博客园. 请关注我的新博客: http://kunyashaw.com/
- IOS开发学习笔记038-autolayout 自动布局 界面实现
在storyboard/xib文件中实现自动布局 autolayout 1.注意事项 autolayout和frame属性是有冲突的,所以如果准备使用autolayout,就不要再代码中对控件的fra ...
- Python-S9-Day126——Scrapy爬虫框架
01 今日内容概要 02 内容回顾和补充:scrapy 03 内容回顾和补充:网络和并发编程 04 Scrapy爬虫框架:pipeline做持久化(一) 05 Scrapy爬虫框架:pipeline做 ...
- c++ 吕凤翥 第五章 类对象一
一 类的声明和实现 1. class tdate //声明部分 { public: void setdate(int y,int m,int d); int isleapyear(); voi ...
- ALPHA(五)
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...