• 【手撸一个ORM】第二步、封装实体描述和实体属性描述


    一、实体属性描述 [MyProperty.cs]

    • Name,属性名称
    • PropertyInfo,反射获取的属性信息,后面很多地方需要通过该属性获取对应的实体类型,或调用SetValue进行赋值
    • FieldName,对应的数据表列名
    • IsKey,是否主键
    • IsMap,查询时是否映射该属性,若属性非值类型或string,则默认为false,其他默认为true;若需手动设置为false,如计算属性,需要在MyColumnAttribute中配置 IsMap=false
    • InsertIgnore,插入时忽略
    • UpdateIgnore,更新时忽略
    • JoinAble,是否可以通过Join进行查询,等同于导航属性
    • ForignKey,如果可以通过Join查询,对应的外键名
    • MasterKey,如果可以通过Join查询,对应的主表Id,默认为Id,若主表主键列名不是Id,需手动在MyForeignKey中配置 MasterKey="StudentId"
    using System.Reflection;
    
    namespace MyOrm.Reflections
    {
        public class MyProperty
        {
            public string Name { get; set; }
    
            public PropertyInfo PropertyInfo { get; set; }public string FieldName { get; set; }
    
            public bool IsKey { get; set; }
    
            public bool IsMap { get; set; } = true;
    
            public bool InsertIgnore { get; set; }
    
            public bool UpdateIgnore { get; set; }
    
            public bool JoinAble { get; set; }
    
            public string ForeignKey { get; set; }
    
            public string MasterKey { get; set; }
    
            public MyProperty(PropertyInfo property)
            {
                Name = property.Name;
                TypeName = property.PropertyType.Name;
                PropertyInfo = property;
    
                if (property.IsMapAble())
                {
                    // 判断是否主键
                    var keyAttribute = property.GetKeyAttribute();
                    if (keyAttribute != null)
                    {
                        //
                        IsKey = true;
                        FieldName = string.IsNullOrWhiteSpace(keyAttribute.FieldName) ? Name : keyAttribute.FieldName;
                        if (keyAttribute.IsIncrement)
                        {
                            // 如果是自增列,不能插入和修改
                            InsertIgnore = true;
                            UpdateIgnore = true;
                        }
                        else
                        {
                            // 如果不是自增列,可插入但不能修改
                            InsertIgnore = true;
                        }
                    }
                    else if (Name == "Id")
                    {
                        FieldName = "Id";
                        IsKey = true;
                        InsertIgnore = true;
                        UpdateIgnore = true;
                    }
                    else
                    {
                        // 可映射的属性
                        var columnAttribute = property.GetMyColumnAttribute();
    
                        if (columnAttribute != null)
                        {
                            FieldName = string.IsNullOrWhiteSpace(columnAttribute.ColumnName)
                                ? Name
                                : columnAttribute.ColumnName;
                            InsertIgnore = columnAttribute.Ignore || columnAttribute.InsertIgnore;
                            UpdateIgnore = columnAttribute.Ignore || columnAttribute.UpdateIgnore;
                        }
                        else
                        {
                            FieldName = Name;
                        }
                    }
                }
                else if (property.IsJoinAble())
                {
                    // 可关联查询的属性
                    IsMap = false;
                    JoinAble = true;
                    UpdateIgnore = true;
                    InsertIgnore = true;
                    var foreignAttribute = property.GetForeignKeyAttribute();
                    if (foreignAttribute == null)
                    {
                        ForeignKey = Name + "Id";
                        MasterKey = "Id";
                    }
                    else
                    {
                        ForeignKey = string.IsNullOrWhiteSpace(foreignAttribute.ForeignKey)
                            ? Name + "Id"
                            : foreignAttribute.ForeignKey;
                        MasterKey = string.IsNullOrWhiteSpace(foreignAttribute.MasterKey)
                            ? "Id"
                            : foreignAttribute.MasterKey;
                    }
                }
                else
                {
                    // 其他属性
                    IsMap = false;
                    UpdateIgnore = true;
                    InsertIgnore = true;
                }
            }
        }
    }

    二、数据实体描述 [MyEntity.cs]

    • KeyColumn,数据表中主键列名称
    • Name,实体名称
    • TableName,实体对应的数据表名称
    • IsSoftDelete,是否软删除(继承ISoftDelete),后面会有说明
    • IsCreateAudit,是否创建审计(保存创建人、创建时间)
    • IsUpdateAudit,是否更新审计(保存修改人、修改时间)
    • Properties,封装过的属性信息列表-考虑过这里用字典保存,但是因为后面需要大量的遍历操作,个人感觉还是List用起来方便,所以最终选择了List类型
    using MyOrm.Attributes;
    using MyOrm.Commons;
    using System;
    using System.Collections.Generic;
    
    namespace MyOrm.Reflections
    {
        public class MyEntity
        {
            public string KeyColumn { get; set; }
    
            public string Name { get; set; }
    
            public string TableName { get; set; }
    
            public bool IsSoftDelete { get; set; }
    
            public bool IsCreateAudit { get; set; }
    
            public bool IsUpdateAudit { get; set; }
    
            public List<MyProperty> Properties { get; set; }
    
            public MyEntity(Type type)
            {
                Name = type.Name;
                IsSoftDelete = type.IsInstanceOfType(typeof(ISoftDelete));
                IsCreateAudit = type.IsInstanceOfType(typeof(ICreateAudit));
                IsUpdateAudit = type.IsInstanceOfType(typeof(IUpdateAudit));
    
                var tableAttr = type.GetCustomAttributes(typeof(MyTableAttribute), false);
                if (tableAttr.Length > 0)
                {
                    var tableName = ((MyTableAttribute)tableAttr[0]).TableName;
                    TableName = string.IsNullOrWhiteSpace(tableName) ? type.Name.Replace("Entity", "") : tableName;
                }
                else
                {
                    TableName = Name;
                }
    
                Properties = new List<MyProperty>();
    
                foreach (var propertyInfo in type.GetProperties())
                {
                    var property = new MyProperty(propertyInfo);
                    if (property.IsKey)
                    {
                        KeyColumn = property.FieldName;
                    }
                    Properties.Add(property);
                }
            }
        }
    }

    三、实体容器

    上面对实体及其属性进行了封装,但是如果每次都需要反射获取,那性能损耗会非常厉害,因此将生成的内容缓存在起来便十分必要了。这里使用的是线程安全的静态字典作为缓存容器。

    using System;
    using System.Collections.Concurrent;
    
    namespace MyOrm.Reflections
    {
        public class MyEntityContainer
        {
            private static readonly ConcurrentDictionary<string, MyEntity> Dict = 
                new ConcurrentDictionary<string, MyEntity>();
    
            public static MyEntity Get(Type type)
            {
                if (type == null) throw new ArgumentNullException(nameof(type));
                if (Dict.TryGetValue(type.FullName ?? throw new InvalidOperationException(), out var result))
                {
                    return result;
                }
                else
                {
                    var entity = new MyEntity(type);
                    Dict.TryAdd(type.FullName, entity);
                    return entity;
                }
            }
        }
    }
  • 相关阅读:
    重构了一波代码,聊聊后端也聊聊游戏后端
    浅谈游戏开发中常见的设计模式
    一次查内存泄露
    sql语句技巧
    python后端链接数据库-----MySQLdb
    web的应用模式
    静态文件
    django配置文件
    视图
    django子应用
  • 原文地址:https://www.cnblogs.com/diwu0510/p/10663339.html
Copyright © 2020-2023  润新知