• PetaPoco源代码学习--2.TableInfo、ColumnInfo类和Cache类


      当把常用的特性填写到POCO实体类时,执行数据库操作时,需要根据实体类上的特性信息进行相应的操作,PetaPoco中的TableInfo和ColumnInfo类就是用来保存实体类上的特性信息。

    TableInfo用来保存数据库表的信息,包括TableName,PrimaryKey,主键是否自增字段,使用Oracle数据库时的Sequence名称。

    ColumnInfo用来保存数据库表的列信息,包括ColumnName,是否结果列(不用更新数据库),数据库列类型是否转换为UTC时间、更新模板和插入模板。

      通过POCO实体类获取到其对应的数据库表和数据库列的信息,就可以使用这些信息对数据库表执行增删改查的操作。

    TableInfo包括一个静态方法,参数为POCO实体类的Type对象,从该对象上获取自定义特性信息来初始化TableInfo实例。

     1     /// <summary>
     2     /// POCO实体类对应的数据库表信息
     3     /// </summary>
     4     public class TableInfo
     5     {
     6         /// <summary>
     7         ///  数据库表名
     8         /// </summary>
     9         public string TableName { get; set; }
    10 
    11         /// <summary>
    12         /// 数据库表主键
    13         /// </summary>
    14         public string PrimaryKey { get; set; }
    15 
    16         /// <summary>
    17         /// 主键是否自增
    18         /// </summary>
    19         public bool AutoIncrement { get; set; }
    20 
    21         /// <summary>
    22         /// Oracle数据自增主键对应的Sequence名称
    23         /// </summary>
    24         public string SequenceName { get; set; }
    25         
    26         /// <summary>
    27         /// 从POCO实体类的特性上初始化TableInfo实例
    28         /// </summary>
    29         public static TableInfo FromPoco(Type t)
    30         {
    31             TableInfo ti = new TableInfo();
    32             //从TableNameAttribute上获取数据表名称,若不存在则使用POCO实体类的名称
    33             var a = t.GetCustomAttributes(typeof(TableNameAttribute), true);
    34             ti.TableName = a.Length == 0 ? t.Name : (a[0] as TableNameAttribute).Value;
    35 
    36             //从PrimaryKeyAttribute上获取数据库表主键名称
    37             a = t.GetCustomAttributes(typeof(PrimaryKeyAttribute), true);
    38             ti.PrimaryKey = a.Length == 0 ? null : (a[0] as PrimaryKeyAttribute).Value;
    39             ti.SequenceName = a.Length == 0 ? null : (a[0] as PrimaryKeyAttribute).SequenceName;
    40             ti.AutoIncrement = a.Length == 0 ? false : (a[0] as PrimaryKeyAttribute).AutoIncrement;
    41             //若不存在PrimaryKeyAttribute,则查找实体类属性中名称为“id"或者实体类名称+“id"或者“_id"的类属性。
    42             if (string.IsNullOrEmpty(ti.PrimaryKey))
    43             {
    44                 var prop = t.GetProperties().FirstOrDefault(p =>
    45                 {
    46                     if (p.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
    47                         return true;
    48                     if (p.Name.Equals(t.Name + "id", StringComparison.OrdinalIgnoreCase))
    49                         return true;
    50                     if (p.Name.Equals(t.Name + "_id", StringComparison.OrdinalIgnoreCase))
    51                         return true;
    52                     return false;
    53                 });
    54                 if (prop != null)
    55                 {
    56                     ti.PrimaryKey = prop.Name;
    57                     ti.AutoIncrement = prop.PropertyType.IsValueType;
    58                 }
    59             }
    60             return ti;
    61         }
    62     }

    ColumnInfo包括一个静态方法,参数为POCO实体类的属性对象,从对象上获取自定义特性信息来初始化ColumnInfo实例

    /// <summary>
        /// POCO实体类属性对应的数据库列信息
        /// </summary>
        public class ColumnInfo
        {
            /// <summary>
            /// 数据库列名称
            /// </summary>
            public string ColumnName { get; set; }
    
            /// <summary>
            /// 是否结果值列,是的话,插入和更新操作不使用该属性
            /// </summary>
            public bool ResultColumn { get; set; }
    
            /// <summary>
            /// 若对应的数据库类类型是DateTime,是否强制转换为UTC时间
            /// </summary>
            public bool ForceToUtc { get; set; }
    
            /// <summary>
            /// 插入模板(暂未理解使用)
            /// </summary>
            public string InsertTemplate { get; set; }
    
            /// <summary>
            /// 更新模板(暂未理解使用)
            /// </summary>
            public string UpdateTemplate { get; set; }
    
            /// <summary>
            /// 从POCO实体类属性的特性初始化ColumnInfo
            /// </summary>
            public static ColumnInfo FromProperty(PropertyInfo propertyInfo)
            {
                // 获取属性所属的类实例上是否包括明确表示列信息的标志
                var explicitColumns = propertyInfo.DeclaringType.GetCustomAttributes(typeof(ExplicitColumnsAttribute), true).Length > 0;
    
                // Check for [Column]/[Ignore] Attributes
                var colAttrs = propertyInfo.GetCustomAttributes(typeof(ColumnAttribute), true);
                //属性明确指定列信息时,但是该属性没有列特性,返回null
                if (explicitColumns)
                {
                    if (colAttrs.Length == 0)
                        return null;
                }
                else
                {
                    //没有明确指定时,该属性没有映射到数据库列,返回null
                    if (propertyInfo.GetCustomAttributes(typeof(IgnoreAttribute), true).Length != 0)
                        return null;
                }
                //类具有明确映射信息,则从列特性获取对应的数据信息或者没有明确信息时,则使用属性名称初始化。
                var ci = new ColumnInfo();
                // Read attribute
                if (colAttrs.Length > 0)
                {
                    var colattr = (ColumnAttribute) colAttrs[0];
                    ci.InsertTemplate = colattr.InsertTemplate;
                    ci.UpdateTemplate = colattr.UpdateTemplate;
                    ci.ColumnName = colattr.Name == null ? propertyInfo.Name : colattr.Name;
                    ci.ForceToUtc = colattr.ForceToUtc;
                    if ((colattr as ResultColumnAttribute) != null)
                        ci.ResultColumn = true;
                }
                else
                {
                    ci.ColumnName = propertyInfo.Name;
                    ci.ForceToUtc = false;
                    ci.ResultColumn = false;
                }
                return ci;
            }
        }
      PetaPoco中定义了一个缓存类,内部使用
    ReaderWriterLockSlim读写锁来控制读取和写入(ReaderWriterLockSlim支持多线程读取和单线程写入),
    其公共方法Get的参数为缓存Key和创建函数,当缓存中没有对应的信息时,则使用创建函数创建信息并缓存起来。
    方法内部先获取读取锁获取缓存信息,若没有则获取写入锁,获取后再次确认是否存在缓存信息,主要原因:获取写入锁需要释放之前所有的读写锁,防止在时间差创建了缓存信息。 
     1     /// <summary>
     2     /// 缓存信息类
     3     /// </summary>
     4     internal class Cache<TKey, TValue>
     5     {
     6         /// <summary>
     7         /// 读写锁
     8         /// </summary>
     9         private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    10 
    11         /// <summary>
    12         /// 存储数据的字典
    13         /// </summary>
    14         private Dictionary<TKey, TValue> _map = new Dictionary<TKey, TValue>();
    15 
    16         /// <summary>
    17         /// 缓存数据的数目
    18         /// </summary>
    19         public int Count
    20         {
    21             get { return _map.Count; }
    22         }
    23 
    24         /// <summary>
    25         /// 根据Key获取对应的数据,若没有数据,则创建它并缓存起来
    26         /// </summary>
    27         public TValue Get(TKey key, Func<TValue> factory)
    28         {
    29             _lock.EnterReadLock();//设置读锁
    30             TValue val;
    31             try
    32             {
    33                 if (_map.TryGetValue(key, out val))
    34                     return val;
    35             }
    36             finally
    37             {
    38                 _lock.ExitReadLock();//释放读锁
    39             }
    40             _lock.EnterWriteLock();//没有找到,设置写锁
    41             try
    42             {
    43                 //再次检测,避免等待获取写锁的时间差中已创建信息
    44                 if (_map.TryGetValue(key, out val))
    45                     return val;
    46                 //使用传入的创建方法创建信息并缓存起来
    47                 val = factory();
    48                 _map.Add(key, val);
    49                 return val;
    50             }
    51             finally
    52             {
    53                 _lock.ExitWriteLock();//释放写锁
    54             }
    55         }
    56 
    57         //清空缓存信息
    58         public void Flush()
    59         {
    60             _lock.EnterWriteLock();
    61             try
    62             {
    63                 _map.Clear();
    64             }
    65             finally
    66             {
    67                 _lock.ExitWriteLock();
    68             }
    69         }
    70     }
    
    
  • 相关阅读:
    ros 使用命令测试topic
    python unicode
    python ros 回充demo
    python ros 回充调用demo
    flask报错No module named 'flask.ext'
    python flask 接口
    ros 安装c++编译的可执行文件
    Linux-Ubuntu14.04下mongodb安装部署
    如何在Ubuntu 14.04中安装最新版Eclipse
    ubuntu 14.04 安装redis5.0.3
  • 原文地址:https://www.cnblogs.com/DreamOfLife/p/9119098.html
Copyright © 2020-2023  润新知