设为首页 收藏本站
查看: 1158|回复: 0

[经验分享] 提高生产性工具(五)

[复制链接]

尚未签到

发表于 2015-7-6 09:42:53 | 显示全部楼层 |阅读模式
  
  在下面流水账似的文章之前,先将一些感悟说一下。
  1.如果一个系统对于某个功能在至少三个地方使用的话,必须将其抽象提炼出来,而且时间点最好是大规模测试之前。
  2.提炼出来的功能,如果品质做得好,整个系统的品质也提高不少。
  3.提炼出一个泛用的功能需要高度的技巧很时间,但是对于后期维护,应对需求变更是非常有好处的,甚至可以通过仅仅修改模型的特性就完成需求变更。
  4.任何一个三年以上的CSharper都可以写一个性能和品质不错的功能,但是要将一个功能做到泛用,具有高度的可扩展性,需要10年左右的经验,大龄程序员应该多关注业务,多思考如何做个泛用功能,不是被多变的需求牵着鼻子走。泛用的东西,先苦后甜。
  5.设计模式不是背书,在于灵活应用,设计模式不是死的,有时候,有些需求需要模式之间的组合,以及一些模式的变体。
  
  关于MongoDB
  MongoDB的好处是
  你可以摆脱固定数据表字段的约束。
  原生天然支持ORM(阶层结构的数据库,就是为了OOP对象而生的)。
  某些方面拥有比SQL更灵活的Query。
  MongoDB的坏处是
  如果你删除一个字段,或者修改一个字段,在序列化的时候就会出错(系统发现一个在新的实体中不存在的属性。。)。而且不想Relation那样,可以通过一个SQL语句就改变表结果,后期维护会有一些额外成本。
  以下内容可以忽略:
  随着大量数据的采集,数据的过滤和可视化将越来越多的出现在实际需求中.
  如何制作一个泛用的数据过滤器和可视化设定器,则是一个新的课题.
  这里数据库使用的是MongoDB,由于MongoDB在Query上的一些特点,数据过滤变得十分简单了.
  假设我们有一张名为人才储备的表格,上面有很多字段,哪些字段是可以用来做过滤的,过滤器的类型是什么,我们在写实体代码的时候,其实可以使用 Attribute 进行标注,然后在运行时,通过读取这些标记,就可以获得可用的过滤器列表.



using System;
namespace BussinessLogic.Entity
{
[AttributeUsage(AttributeTargets.Property)]
public class FilterItemAttribute : Attribute
{
///
/// 数据形式枚举
///
public enum StructType
{
SingleMasterTable = 0,
MultiMasterTable = 5,
SingleEnum = 10,
MultiEnum = 15,
Datetime = 20,
Boolean = 25,
SingleMasterTableWithGrade =30,
MultiMasterTableWithGrade = 35,
SingleCatalogMasterTable = 40,
MultiCatalogMasterTable = 45
}
///
/// 数据形式
///
public StructType MetaStructType { get; set; }
///
/// 元数据类型
///
public Type MetaType { get; set; }
}
}
  如果某个字段是可以多选的,可选值是从MasterTable来的,它就是MultiMasterTable,单选的,则是Single。如果可选值是来自于枚举的,则MasterTable变为Enum。
  下面将这些特性作用于具体的实体类



using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using MongoDB.Bson.Serialization.Attributes;
using System;
namespace BussinessLogic.Entity
{
///
///     人才储备
///
public partial class TalentInfo : CompanyTable
{
#region "model"
///
///     姓名
///
[DisplayName("姓名")]
[Required]
public string Name { get; set; }
///
///     英语名
///
[DisplayName("英语名")]
public string EnglishName { get; set; }
///
///     生日
///
[DisplayName("生日")]
[Required]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime BirthDay { get; set; }
///
///     出生地
///
[DisplayName("出生地")]
public string BornIn { get; set; }
///
///     常住地
///
[DisplayName("常住地")]
[Required]
public string Location { get; set; }
///
///     手机
///
[DisplayName("手机")]
[Required]
[DataType(DataType.PhoneNumber)]
[RegularExpression(@"^1[3458][0-9]{9}$", ErrorMessage = "手机号格式不正确")]
public string Mobile { get; set; }
///
///     电子邮件
///
[DisplayName("电子邮件")]
[Required]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
///
///     大学
///
[DisplayName("大学")]
[Required]
public string University { get; set; }
///
///     专业
///
[DisplayName("专业")]
[Required]
public string Major { get; set; }
///
///     学位
///
[DisplayName("学位")]
[UIHint("Enum")]
public AcademicType Academic { get; set; }
///
/// 海外工作背景
///
[DisplayName("海外工作背景")]
[FilterItem(MetaStructType = FilterItemAttribute.StructType.Boolean)]
public bool OverseaWork { get; set; }
///
/// 海外教育背景
///
[DisplayName("海外教育背景")]
[FilterItem(MetaStructType = FilterItemAttribute.StructType.Boolean)]
public bool OverseaEdu { get; set; }
///
///     行业背景
///
[DisplayName("行业背景")]
public List IndustryBackgroundList { get; set; }
///
///     上一家公司
///
[DisplayName("上一家公司")]
public string PreEmp { get; set; }
///
///     上一家公司行业
///
[DisplayName("上一家公司行业")]
public string PerInd { get; set; }
///
///     招聘渠道
///
[DisplayName("招聘渠道")]
public string Channel { get; set; }
///
///     语言
///
[DisplayName("语言")]
[FilterItem(MetaStructType = FilterItemAttribute.StructType.MultiMasterTableWithGrade, MetaType = typeof(M_Language))]
public List LanguageList { get; set; }
///
///     技能
///
[DisplayName("技能")]
[FilterItem(MetaStructType = FilterItemAttribute.StructType.MultiCatalogMasterTable , MetaType = typeof(M_Skill))]
public List SkillList { get; set; }
///
///     等级
///
[DisplayName("等级")]
[UIHint("Enum")]
[Required]
public CommonGrade TalentRank { get; set; }
///
///     评价
///
[DisplayName("评价")]
public string Evaluate { get; set; }
///
///     评价
///
[DisplayName("备注")]
public string Comment { get; set; }

///
///     数据集名称
///
public override string GetCollectionName()
{
return "TalentInfo";
}
///
///     数据集名称静态字段
///
public static string CollectionName = "TalentInfo";

///
///     数据主键前缀
///
public override string GetPrefix()
{
return string.Empty;
}
///
///     数据主键前缀静态字段
///
public static string Prefix = string.Empty;
///
///     Mvc画面的标题
///
[BsonIgnore] public static string MvcTitle = "人才储备";
#endregion
}
}
   系统将自动通过反射机制获得FilterItemAttribute特性,根据特性来生成过滤器项目(filterItem)。
    由于是动态的,所以,很容易的增加和修改过滤器项目(filterItem)。
    过滤器项目(filterItem)也分多种类型,例如一个布尔型过滤器项目,则负责诸如 “过滤出全部具有 海外工作经验 的人”这样的任务。
  



using MongoDB.Driver;
using MongoDB.Driver.Builders;
namespace BussinessLogic.Entity
{
///
/// 布尔型的过滤器
///
public class FilterItemBoolean : FilterItemBase
{
///
/// 是否
///
public bool YesOrNo;
public FilterItemBoolean(string _FieldName)
{
FieldName = _FieldName;
IsActive = false;
}
///
/// 获得Query
///
///
public override IMongoQuery GetQuery()
{
return Query.EQ(FieldName, YesOrNo);
}
}
}
  每个过滤器,一旦属性设定完成,MongoDB的查询条件则也可以自动获得了。例如上面代码的 Query.EQ(FieldName, YesOrNo)
  表示一个查询条件 :记录的名为 FieldName的元素的值为 YesOrNo(EQ表示等于)。
  多个子条件可以组合成一个真正的过滤器(FilterSet)。当然,由于过滤器项目的过滤条件是自动获得的,所以整个过滤器的过滤条件也是很容易直接获得的。



using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver;
using System.ComponentModel;
using MongoDB.Driver.Builders;
using System;
using System.Collections.Generic;
using InfraStructure.DataBase;
namespace BussinessLogic.Entity
{
///
///     过滤器中心
///
public class FilterSetCenter : FilterSetBase
{
#region "model"
///
///     数据集名称
///
public override string GetCollectionName()
{
return "FilterSetCenter";
}
///
///     数据集名称静态字段
///
public static string CollectionName = "FilterSetCenter";

///
///     数据主键前缀
///
public override string GetPrefix()
{
return string.Empty;
}
///
///     数据主键前缀静态字段
///
public static string Prefix = string.Empty;
///
///     Mvc画面的标题
///
        [BsonIgnore]
public static string MvcTitle = "过滤器中心";
///
/// 设定DisplayName
///
public void SetDisplayName()
{
// 考虑到DisplayName和FieldName的关联性
// 以及DisplayName可能会修改名称
var type = Type.GetType(ModelName);
for (int i = 0; i < FilterItems.Count; i++)
{
FilterItems.DisplayName = EasyQuery.GetDisplayName(FilterItems.FieldName, type);
}
}
///
///
///
///
///
///
///
public static List GetFilterWrapperList(string CompanyId, string AccountCode)
{
var FilterMaster = new List();
var CompanyIdQuery = EasyQuery.CompanyIdQuery(CompanyId);
var AccountIdQuery = EasyQuery.AccountCodeQuery(AccountCode);
var ModelNameQuery = Query.EQ("ModelName", typeof(T).FullName);
var FilterQuery = Query.And(CompanyIdQuery, AccountIdQuery, ModelNameQuery);
var FilterSetList = InfraStructure.DataBase.Repository.GetRecList(FilterSetCenter.CollectionName, FilterQuery);
foreach (var filter in FilterSetList)
{
FilterMaster.Add(new MasterWrapper
{
Code = filter.Code,
Rank = int.Parse(filter.Code),
Name = filter.Name,
Description = filter.Description
});
}
return FilterMaster;
}
///
/// 获得查询
///
///
public IMongoQuery GetQuery()
{
IMongoQuery FilterItemQuery = EasyQuery.CompanyIdQuery(CompanyId);
foreach (var item in FilterItems)
{
if (item.IsActive)
{
switch (item.GetType().Name)
{
case "FilterItemList":
FilterItemList filterItemList = (FilterItemList)item;
if (filterItemList.Itemlist.Count > 0)
{
FilterItemQuery = Query.And(FilterItemQuery, filterItemList.GetQuery());
}
break;
case "FilterItemWithGradeList":
FilterItemWithGradeList filterItemWithGradeList = (FilterItemWithGradeList)item;
if (filterItemWithGradeList.Itemlist.Count > 0)
{
FilterItemQuery = Query.And(FilterItemQuery, filterItemWithGradeList.GetQuery());
}
break;
default:
FilterItemQuery = Query.And(FilterItemQuery, item.GetQuery());
break;
}
}
}
return FilterItemQuery;
}
#endregion
}
}
GetQuery()方法负责通过 MongoDB的 Query.And 方法将子条件组合在一起。当然,现在默认所有过滤器之间是And连接,稍加修改之后也可以用Or连接。
过滤器配合UI之后,可以动态的生成如下的HTML画面。完全不需要任何多余的代码。


DSC0000.png


下面这样一段代码就可以构成任意的过滤器编辑界面了。
当然这里需要大约 500行的UI自动生成代码的支持。


@model FilterSetCenter
@{
ViewBag.Title = "";
if (Model.Code == ConstHelper.NewRecordCode)
{
ViewBag.Title = "创建-" + FilterSetCenter.MvcTitle;
}
else
{
ViewBag.Title = "编辑-" + FilterSetCenter.MvcTitle;
}
Layout = "~/Views/Shared/_DashBoardForMin.cshtml";
}
@using (Html.BeginForm())
{


@Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })

@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })



@Html.LabelFor(model => model.Description, new { @class = "control-label col-md-2" })

@Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Description, "", new { @class = "text-danger" })


@foreach (FilterItemBase item in Model.FilterItems)
{

@Html.Label(item.DisplayName, new { @class = "control-label col-md-2" })

@(FilterHelper.GetFilter(item, ViewBag.CompanyId))


}



@Html.ActionLink("返回列表", "Index", null, new { @class = "btn btn-default" })



}
  UI辅助代码基本上完成的是类似于 html.EditFor这样的功能,也就是对于HTML代码的一个封装。例如,下面的代码生成一个面板。上面画面例子中,技能的面板也就是这样生成的。当然,整个画面由多个这样的UI辅助代码的共同协作才可以完成。一个方法错了,整个画面就可能出问题。但是如果可以控制每个方法的品质,则使用这些方法堆砌出来的界面的品质也是有保证的。



        ///
/// 获得一个面板
///
///
///
///
///
public static MvcHtmlString GetPanel(string id, string strTitle, string strContent)
{
var html = "" + Environment.NewLine;
html += "" + Environment.NewLine;
html += "" + Environment.NewLine;
html += "" + Environment.NewLine;
html += strTitle  + Environment.NewLine;
html += ""  +Environment.NewLine;
html += "" + Environment.NewLine;
html += "" + Environment.NewLine;
html += "" + Environment.NewLine;
html += strContent + Environment.NewLine;
html += "" + Environment.NewLine;
html += "" + Environment.NewLine;
return new MvcHtmlString(html);
}
  
  


  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-83704-1-1.html 上篇帖子: mongodb的常用操作 下篇帖子: MongoDB的学习--文档的插入、删除和更新
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表