实体类(多层嵌套)生成FastReport需要的frd字典文件

发布时间 2023-12-04 11:32:10作者: Smile灬Lucky
 #region 根据模型生成FastReport需要的Frd字典文件
        /// <summary>
        /// 生成frd文件内容
        /// </summary>
        private static StringBuilder stringTouBu = new StringBuilder();

        /// <summary>
        /// 根据模型生成FastReport需要的Frd字典文件
        /// </summary>
        /// <param name="model">实体模型</param>
        /// <param name="path">生成的frd存放的路径(后面不要带\)</param>
        /// <param name="bindName">FastReport数据绑定名称,默认取实体模型名称</param>
        /// <returns></returns>
        /// <remarks>
        /// Request by OP需要用FastReport Reponse by Smile 2022-08-03
        /// </remarks>
        public static string GenerateFRD<T>(this T model, string path, string bindName = null)
        {
            var t = model.GetType();
            var properties = t.GetProperties();

            stringTouBu.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            stringTouBu.AppendLine("<Dictionary>");
            stringTouBu.AppendLine($"<BusinessObjectDataSource Name=\"{bindName ?? t.Name}\" ReferenceName=\"{bindName ?? t.Name}\" DataType=\"System.Int32\" Enabled=\"true\">");

            foreach (var item in properties)
            {
                var name = item.Name;
                var type = item.PropertyType.Name;
                var isClass = item.PropertyType.IsClass;//获取一个值,该值指示 System.Type 是类还是委托; 也就是说,不是值类型或接口。
                var isGenericType = item.PropertyType.IsGenericType;//获取一个值,该值指示当前类型是否为泛型类型。
                var fullName = item.PropertyType.FullName;
                //                   表示实体模型                              表示数组
                if ((type != "String" && isClass && !isGenericType) || (isClass && isGenericType))
                {
                    GenerateType(item.PropertyType, name);
                }
                else
                {
                    stringTouBu.AppendLine($"<Column Name=\"{name}\" DataType=\"{GetType(type, fullName)}\" PropName=\"Column\"/>");
                }
            }
            stringTouBu.AppendLine("</BusinessObjectDataSource>");
            stringTouBu.AppendLine("</Dictionary>");

            string filePath = $"{path}\\{bindName ?? t.Name}.frd";
            if (!File.Exists(filePath))
            {
                File.Create(filePath);
            }
            System.IO.File.WriteAllText(filePath, stringTouBu.ToString());

            return stringTouBu.ToString();
        }

        /// <summary>
        /// 递归获取多层嵌套的模型
        /// </summary>
        /// <param name="t">模型(单个模型或者数组)</param>
        /// <param name="bindName">数据源绑定的名称</param>
        /// <returns></returns>
        private static void GenerateType(Type t, string bindName)
        {
            stringTouBu.AppendLine($"<BusinessObjectDataSource Name=\"{bindName}\" ReferenceName=\"{bindName}\" DataType=\"System.Int32\" Enabled=\"true\">");

            var count = t.GenericTypeArguments.Length;
            var properties = count > 0 ? t.GenericTypeArguments[0].GetProperties() : t.GetProperties();
            foreach (var item in properties)
            {
                var name = item.Name;
                var type = item.PropertyType.Name;
                var isClass = item.PropertyType.IsClass;//获取一个值,该值指示 System.Type 是类还是委托; 也就是说,不是值类型或接口。
                var isGenericType = item.PropertyType.IsGenericType;//获取一个值,该值指示当前类型是否为泛型类型。
                var fullName = item.PropertyType.FullName;
                //                   表示实体模型                              表示数组
                if ((type != "String" && isClass && !isGenericType) || (isClass && isGenericType))
                {
                    GenerateType(item.PropertyType, name);
                }
                else
                {
                    stringTouBu.AppendLine($"<Column Name=\"{name}\" DataType=\"{GetType(type, fullName)}\" PropName=\"Column\"/>");
                }
            }
            stringTouBu.AppendLine("</BusinessObjectDataSource>");
        }

        /// <summary>
        /// 获取数据类型空间
        /// </summary>
        /// <param name="type">原始type类型</param>
        /// <param name="fullName"></param>
        /// <returns></returns>
        private static string GetType(string type, string fullName)
        {
            //判断值类型是否可为空 System.Nullable`1 固定的命名空间
            if (type == "Nullable`1")
            {
                //可为空则获取不为空的命名类型
                return fullName.Replace("System.Nullable`1[[", "").Replace("]]", "").Split(',')[0];
            }
            return fullName;
        } 
        #endregion