欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#根据反射和特性实现ORM映射实例分析

程序员文章站 2023-11-27 13:11:34
本文实例讲述了c#根据反射和特性实现orm 映射的方法。分享给大家供大家参考。具体如下: (一)关于反射 什么是反射? 反射就是在运行时,动态获取对象信息的方法。比如...

本文实例讲述了c#根据反射和特性实现orm 映射的方法。分享给大家供大家参考。具体如下:

(一)关于反射

什么是反射?

反射就是在运行时,动态获取对象信息的方法。比如:运行时获得对象有哪些属性,方法,委托等。

反射的作用?

能够实现运行时,动态调用对象的方法,以及动态设置、获取属性值等。

反射的示例:

using system;
using system.reflection;
namespace cs_test
{
  public class mystudent
  {
    private string sname;
    public string sname
    {
      get { return sname; }
      set { sname = value; }
    }
    private int sage;
    public int sage
    {
      get { return sage; }
      set { sage = value; }
    }
  }
  class test_attribute
  {
    [stathread]
    static void main(string[] args)
    {
      mystudent stu1 = new mystudent();
      stu1.sname = "刘德华";
      stu1.sage = 40;
      // 获得所有属性
      propertyinfo[] pros = stu1.gettype().getproperties();
      // 显示所有属性值
      foreach (propertyinfo pro in pros)
       console.writeline(pro.name+":"+pro.getvalue(stu1,null));
      //更改stu1对象的sage值
      stu1.gettype().getproperty("sage").setvalue(stu1, 30, null);
      // 显示所有属性值
      foreach (propertyinfo pro in pros)
       console.writeline(pro.name+":"+pro.getvalue(stu1, null));
    }
  }
}

(二)关于特性

什么是 attribute?

它是对运行时的对象或对象的属性、方法、委托等进行描述的类。
attribute 的作用?
用于在运行时,描述你的代码或者影响你的程序的行为。

注意:

既然attribute 是类,那么它的定义与定义类一样。
唯一不同的就是,自定义attribute 类必须继承于system.attribute 空间。
特性的示例:

//描述数据库字段的 attribute
public class datafieldattribute : attribute
{
    public datafieldattribute(string fieldname,string fieldtype)
    {
      this._fieldname = fieldname;
      this._fieldtype = fieldtype;
    }
    // 数据库字段名
    private string _fieldname;
    public string fieldname
    {
      get { return _fieldname; }
      set { _fieldname = value; }
    }
    // 数据库字段类型
    private string _fieldtype;
    public string fieldtype
    {
      get { return _fieldtype; }
      set { _fieldtype = value; }
    }
}

通过自定义attribute,我们定义了类属性和数据库字段的一一对应关系,于是对mystudent 类的name、age 属性都加上attribute 的描述,指定他们对应的数据库字段名以及类型。
代码更改如下:

public class mystudent
{
    private string _name;
    //使用“特性”描述对应的数据库字段名、类型
    [datafieldattribute("sname", "varchar")]
    public string name
    {
      get { return _name; }
      set { _name = value; }
    }
    private int _age;
    [datafieldattribute("sage", "int")]
    public int age
    {
      get { return _age; }
      set { _age = value; }
    }
}

(三)orm 映射规则的定义

给实体类增加datafieldattribute 的描述,其实就是增加了o(对象)/ r(关系数据库)的映射规则。
下面我们就通过反射的方法实现:在运行时动态获取o/r  mapping 的映射规则:

static void main(string[] args)
{
  mystudent stu1 = new mystudent();
  stu1.name = "刘德华";
  stu1.age = 40;
  //通过反射的方法来动态获取此映射规则
  propertyinfo[] infos = stu1.gettype().getproperties();
  object[] objs_fieldattr = null;
  foreach (propertyinfo info in infos)
  {
    // getcustomattributes: 
    // 返回实体对象中每个属性对应的“特性”信息(数据库字段名、类型)
    objs_fieldattr = info.getcustomattributes(
               typeof(datafieldattribute), false);
    if (objs_fieldattr != null)
    {
      console.write("实体类的属性名:" + info.name);
      console.write(" -> 数据库字段名:");
      console.writeline(((datafieldattribute)objs_fieldattr[0]).fieldname);
    }
  }
}

显示结果:

实体类的属性名:name -> 数据库字段名:sname
实体类的属性名:age -> 数据库字段名:sage
 
接下来的工作就是:怎样根据这种方法动态地从对象中获取映射规则,然后动态构造insert、update、delete 等 sql 语句。这就是实现自己的orm 的原理。
 
这里的代码仅仅是举例,而要真正实现一个orm,我们还需要考虑的很多,比如:

1、实体类对应于哪张数据库表?
2、数据库表中的 pk  和 fk(如果有的话)怎么表示?

完整代码如下:

using system;
using system.reflection;
namespace cs_test
{
  public class mystudent
  {
    private string _name;
    //使用“特性”描述对应的数据库字段名、类型
    [datafieldattribute("sname", "varchar")]
    public string name
    {
      get { return _name; }
      set { _name = value; }
    }
    private int _age;
    [datafieldattribute("sage", "int")]
    public int age
    {
      get { return _age; }
      set { _age = value; }
    }
  }
  //描述数据库字段的 attribute
  public class datafieldattribute : attribute
  {
    public datafieldattribute(string fieldname,string fieldtype)
    {
      this._fieldname = fieldname;
      this._fieldtype = fieldtype;
    }
    // 数据库字段名
    private string _fieldname;
    public string fieldname
    {
      get { return _fieldname; }
      set { _fieldname = value; }
    }
    // 数据库字段类型
    private string _fieldtype;
    public string fieldtype
    {
      get { return _fieldtype; }
      set { _fieldtype = value; }
    }
  }
  class test_attribute
  {
    [stathread]
    static void main(string[] args)
    {
      mystudent stu1 = new mystudent();
      stu1.name = "刘德华";
      stu1.age = 40;
      // 获得所有属性
      propertyinfo[] pros = stu1.gettype().getproperties();
      // 显示所有属性值
      foreach (propertyinfo pro in pros)
       console.writeline(pro.name+":"+pro.getvalue(stu1,null));
      //更改stu1对象的sage值
      stu1.gettype().getproperty("age").setvalue(stu1, 30, null);
      // 显示所有属性值
      foreach (propertyinfo pro in pros)
       console.writeline(pro.name+":"+pro.getvalue(stu1, null));

      //通过反射的方法来动态获取此映射规则
      propertyinfo[] infos = stu1.gettype().getproperties();
      object[] objs_fieldattr = null;
      foreach (propertyinfo info in infos)
      {
        // getcustomattributes: 
        // 返回实体中每个属性对应的“特性”信息(数据库字段名、类型)
        objs_fieldattr = info.getcustomattributes(
                typeof(datafieldattribute), false);
        if (objs_fieldattr != null)
        {
          console.write("实体类的属性名:" + info.name);
          console.write(" -> 数据库字段名:");
          console.writeline(((datafieldattribute)objs_fieldattr[0]).fieldname);
        }
      }
    }
  }
}

希望本文所述对大家的c#程序设计有所帮助。