马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
快速认识ORM
对象-关系映射,即Object/Relation Mapping,主要实现程序对象到关系数据库的映射。现在.Net比较流行的ORM框架有:EF、SqlSugar、Dapper、FreeSql、Nhibernate、IBatis.Net等。
O/RM只是一层代码的封装,底层还是基于ADO.NET完成对数据库的访问。
一般写法
如果我们要写一个查询,用ADO.NET就会如下这样写。- private static string ConnectionStringCustomers = "Data Source=.;Database=Customers;" +
- "User ID=sa;Password=123456;MultipleActiveResultSets=True";
- public Company FindCompany(int id)
- {
- string sql = $@"
- SELECT [Id],[Name],[CreateTime],[CreatorId],
- [LastModifierId],[LastModifyTime]
- FROM [dbo].[Company]
- WHERE ID = {id}";
- using (SqlConnection conn = new SqlConnection(ConnectionStringCustomers))
- {
- SqlCommand command = new SqlCommand(sql, conn);
- conn.Open();
- var reader = command.ExecuteReader();
- if (reader.Read())
- {
- Company company = new Company()
- {
- Id = (int)reader["Id"],
- Name = reader["Name"].ToString()
- };
- return company;
- }
- else
- {
- return null;
- }
- }
- }
复制代码- public abstract class BaseModel
- {
- public int Id { set; get; }
- }
- public class Company : BaseModel
- {
- public string Name { get; set; }
- public DateTime CreateTime { get; set; }
- public int CreatorId { get; set; }
- public int? LastModifierId { get; set; }
- public DateTime? LastModifyTime { get; set; }
- }
复制代码 但这样的写法是写死了的,我们能不能写一个通用查询,不管他是哪张表。
通用写法
既然要通用,那就不能写死类型,我们想到了使用泛型。泛型是任何类型都可以用,为了保证类型正确,我们再加泛型约束。
为了得到属性,我们要使用反射获取。- public T Find<T>(int id) where T : BaseModel // 泛型约束,必须继承自BaseModel
- {
- string colums = string.Join(",", typeof(T).GetProperties().Select(p => $"[{p.Name}]").ToArray());
- string sql = $"SELECT {colums} FROM [{typeof(T).Name}] WHERE Id={id}";
- using (SqlConnection conn = new SqlConnection(ConnectionStringCustomers))
- {
- SqlCommand command = new SqlCommand(sql, conn);
- conn.Open();
- var reader = command.ExecuteReader();
- if (reader.Read())
- {
- // 反射实例化
- T t = Activator.CreateInstance<T>();
- foreach (var property in typeof(T).GetProperties())
- {
- property.SetValue(t, reader[property.Name] is DBNull ? null : reader[property.Name]);
- }
- return t;
- }
- else
- {
- return null;
- }
- }
- return default(T);
- }
复制代码 上述的方法,使用泛型和反射使我们的查询可以通用。
然后使用Company Company = sqlHelper.Find(1);来调用得到实体。
但是,我们还有一个问题,如果我们的表名和实体类名称不一样,或字段名不一样,比如:表名为Sys_Company而实体名为Company,那我们该如何映射?
这里我们打算用C#的特性来解决这一问题。
首先,创建用来映射的特性类。- public class AbstractMappingAttribute : Attribute
- {
- public string MappingName = null;
- public AbstractMappingAttribute(string mappingName)
- {
- this.MappingName = mappingName;
- }
- }
复制代码 映射表名。- [AttributeUsage(AttributeTargets.Class)]
- public class DBProxyTableAttribute: AbstractMappingAttribute
- {
- public DBProxyTableAttribute(string tableName) : base(tableName){}
- }
复制代码 映射列名。- [AttributeUsage(AttributeTargets.Property)]
- public class DBProxyColumnAttribute : AbstractMappingAttribute
- {
- public DBProxyColumnAttribute(string columnName):base(columnName) {}
- }
复制代码 在类名上添加特性。- [DBProxyTable("Sys_Company")]
- public class Company : BaseModel
- {
- [DBProxyColumn("Company_Name")]
- public string Name { get; set; }
- ......
- }
复制代码 获取实体类名或属性上的特性值来映射数据库的方法。- public static class DBProxyMappingExtension
- {
- public static string GetMappingName(this MemberInfo member)
- {
- string name = null;
- if (member.IsDefined(typeof(AbstractMappingAttribute), true))
- {
- var attribute = member.GetCustomAttribute<AbstractMappingAttribute>();
- name = attribute.MappingName;
- }
- else
- {
- name = member.Name;
- }
- return name;
- }
- }
复制代码 最后,重新修改通用方法。- public T Find<T>(int id) where T : BaseModel // 泛型约束,必须继承自BaseModel
- {
- //string colums = string.Join(",", typeof(T).GetProperties().Select(p => $"[{p.Name}]").ToArray());
- string colums = string.Join(",", typeof(T).GetProperties().Select(p => $"[{p.GetMappingName()}]").ToArray());
- //string sql = $"SELECT {colums} FROM [{typeof(T).Name}] WHERE Id={id}";
- string sql = $"SELECT {colums} FROM [{typeof(T).GetMappingName()}] WHERE Id={id}";
- using (SqlConnection conn = new SqlConnection(ConnectionStringCustomers))
- {
- SqlCommand command = new SqlCommand(sql, conn);
- conn.Open();
- var reader = command.ExecuteReader();
- if (reader.Read())
- {
- // 反射实例化
- T t = Activator.CreateInstance<T>();
- foreach (var property in typeof(T).GetProperties())
- {
- //property.SetValue(t, reader[property.Name] is DBNull ? null : reader[property.Name]);
- property.SetValue(t, reader[property.GetMappingName()] is DBNull ? null : reader[property.GetMappingName()]);
- }
- return t;
- }
- else
- {
- return null;
- }
- }
- return default(T);
- }
复制代码 |