Skip to content

Latest commit

 

History

History
412 lines (279 loc) · 10.4 KB

File metadata and controls

412 lines (279 loc) · 10.4 KB

开发规范

3.1、命名

3.1.1. 枚举类型,类,枚举值,事件,异常类,接口,方法,命名空间,属性,公共实例字段 使用“首字母和后面连接的每个单词的首字母都大写” 的方式命名。

比如:BaseEntity

3.1.2. 参数,方法内的变量,序列化标签,使用“首字母小写,而每个后面连接的单词的首字母都大写”的方式命名。

比如:defaultValue

3.1.3. 受保护的实例字段,私有的实例字段,静态字段,静态只读字段 使用“_”+格式1命名。

比如:_repository

3.1.4. 常量 使用 “__”+格式1命名。

比如:__Exit

3.1.5. 接口命名需加前缀 “I”+格式1命名。

比如:IWorkContext

3.1.6. 控制器命名采用1的格式。

比如:模块->ModuleController

3.1.7. 业务服务采用“I”+格式1+“Service”命名

比如:IModuleService

3.1.8. 业务实现采用 “格式1”+“Service”命名

比如:ModuleService

3.1.9. 请求对象采用“格式1”+“Request”命名,并且必须继承INGPRequest

比如:TestRequest

3.1.10. 请求返回对象采用“格式1”+“Response”命名

比如:TestResponse

3.1.11. 验证模型采用“格式1”+“Validator”命名

比如:TestRequestValidator

3.1.12. 资源Key采用“格式1”+“功能”命名

比如:TestNameNotEmpty

3.1.13. 每个单词拼写争取,并有意义,不要出现类似“aaa”这种变量

3.1.14 数据库的数据列采用“格式1”命名,数据表采用格式1“大功能”+“_”+“小功能命名”

比如表名为:SysOrg_Employee,列名为:DeptId。注意列不能包含“”,表名只有一个“

3.2、注释

3.2.1. 每个.cs文件顶添加以下注释

/* ---------------------------------------------------------------------
* Copyright:
* IXinWu Technology Co., Ltd. All rights reserved.
*
* {类名} Description:
* {类功能}
*
* Comment                          Revision  Date        Author
* -----------------------------    --------  --------    -----------
* Created                          1.0       {创建日期} {创建者}
*
* ------------------------------------------------------------------------------*/

3.2.2. 每个类定义必须有类说明,比如:

/// <summary>
/// 动态数据服务
/// </summary>
public class DynamicDataService : IDynamicDataService
...

3.2.3. 每个方法有详细的方法说明和参数说明,比如:

/// <summary>
/// 获取列表页面数据
/// </summary>
/// <param name="query">查询对象</param>
/// <returns>查询结果</returns>
public NGPDataPageResponse QueryDynamicListPageData(NGPPageQueryRequest<DynamicQueryRequest> query)
...

3.2.4. 枚举,属性,字段,事件,委托都需有单独的注释

3.3、数据库&LINQ相关

3.3.1. where语句在判断条件为索引字段时不要使用or链接,比如下面对num索引字段的查询

错误:

select id from t where num = 10 or num = 20

正确:

Select id from t where num = 10
Union all
Select id from t where num = 20

3.3.2. 索引字段的参数化查询

错误:

select id from t where num = @num

正确:

Select id from t with(index(索引名)) where num = @num

3.3.3. 不要在where字句中对字段进行表达式操作

错误:

Select id from t where num/2 = 100

正确:

Select id from t where num = 200

3.3.4. 不要在where语句中对索引字段进行函数操作

Select id from t where substring(name,1,3)=’abc’

3.3.5. Where语句 = 的左边不要进行函数,算术表达式或其他运算

3.3.6. 避免使用where 语句的in

错误1:

Select a.name from a where a.id in (select a_id from b where b.name like '%test%')

正确1:

select a.name from a where exists(
  select a_id from b where b.name like '%test%' && a.id =b.a_id)

错误2:

var idList = from item in b where b.name.Container('test') select item.a_id
var nameList = from item in a where idList.Container(item.id) select item.name

正确2:

select distinct a.name from a
inner join b on b.a_id = a.id and b.name like '%test%'

3.3.7. 不要使用select *,需要指定具体字段

3.4、通用规范

3.4.1. 条件表达式嵌套不超过3层

3.4.2. 不要出现重复的代码片段

3.4.3. 能关联获取的数据直接Linq关联而不是单独再查询

3.4.4. 不要有循环内操作数据库查询的情况

3.4.5. 不要对同一个对象重复追加/更新/删除

3.4.6. 代码内不应出现异常的捕获

3.4.7. 类型转换应使用as

3.4.8. 在字符串拼接时应该用StringBuilder.Append,不要使用~~string+=~~的格式。

3.4.9. 对于一个实例方法,如果方法没有参数并且有返回值,把方法改成属性

3.4.10. 移除未使用的局部变量,私有字段,参数

3.4.11. 不要使用ArrayListHashTable

3.4.12. 如果一个类里的所有方法都是静态的,则类也声明为静态的

3.4.13. 需要使用对象类型的常量时,用static readonly修饰。

3.4.14. 一个方法的局部变量不要超过15个。

3.4.15. 不要对浮点类型的数据做等于或不等于判断。

3.4.16. 移除未被使用的代码和注释代码

3.4.17. 代码列宽控制在110字符左右。

3.4.18. 每行只有一个语句,比如避免: a++; b++;

3.4.19. 为所有的swich语句提供default分支。

3.5 系统开发规范

3.5.1. 控制器必须继承:BaseApiController

3.5.2. 控制器的Action必须是Post

3.5.3. 控制的的Action返回必须调用基类的Ok,OkDataResultOkPageDataResult

3.5.4. 模型必须继承:INGPModel

3.5.5. 业务实体必须继承:BaseDBEntity

3.5.6. 系统实体必须继承:BaseEntity

3.5.7. 业务实体映射必须继承:BaseDBEntityMap<TEntity>

3.5.8. 系统实体映射必须继承:BaseEntityMap<TEntity>

3.5.9. 系统所有的错误码都定义在StatusCode中,对应的消息定义在DescriptionAttribute

/// <summary>
/// 操作成功!
/// </summary>
[Description("操作成功!")]
Success = 200,
...
/// <summary>
/// {0}不能为空!
/// </summary>
[Description("{0}不能为空!")]
EmptyError = 2000,

3.5.10. 在业务domain继承IDependencyRegistrar,进行业务接口的注入配置

3.5.11. 在使用'MappingExtensions'的方法时,需要先进行Map配置,并且继承ProfileINGPMapperProfile

/// <summary>
/// demo 模型映射
/// </summary>
public class DemoModelMapProfile : Profile, INGPMapperProfile
{
    /// <summary>
    /// ctor
    /// </summary>
    public DemoModelMapProfile()
    {
        CreateMap<Test_Demo, QueryDemoResponse>();

        CreateMap<CreateDemoRequest, Test_Demo>();
    }

    #region Properties

    /// <summary>
    /// Order of this mapper implementation
    /// </summary>
    public int Order => 1;

    #endregion
}

如下方式使用:

var entity = _unitRepository.FindById<Test_Demo>('id');
var result = entity.ToModel<QueryDemoResponse>();

3.5.12 api的请求对象都必须进行模型验证,比如定义的此Action

/// <summary>
/// crate demo
/// </summary>
/// <param name="request">request info</param>
/// <returns>create result</returns>
[HttpPost("create")]
public ActionResult<NGPResponse> Create(CreateDemoRequest request)
{
    return Ok(_demoService.Create(request));
}

针对CreateDemoRequest我们需要构建CreateDemoRequestValidator,其中CreateDemoRequestValidator必须继承BaseNGPValidator,在构造函数里添加验证:

RuleFor(x => x.Number)
    .NotEmpty()
    .WithStatusCode(StatusCode.EmptyError, "数字")
    .Must(x => x > 10 && x < 50)
    .WithStatusCode(StatusCode.BetweenValueError, "数字", 10,50);

RuleFor(x => x.Email)
    .Must(x =>
    {
        if (string.IsNullOrWhiteSpace(x))
        {
            return true;
        }
        return CommonHelper.IsValidEmail(x);
    })
    .WithStatusCode(StatusCode.FormatError, "邮件", "xxx@xxx.xxx");

消息统一使用WithStatusCode进行添加,可进行数据库验证,只需在构造函数里引入IUnitRepository即可

3.5.13. 对业务进行验证失败时,统一抛出NGPException

var instanceType = instance.GetType();
var pi = instanceType.GetProperty(propertyName);
if (pi == null)
    throw new NGPException(StatusCode.TypeNotPropertyError, propertyName, instanceType.Name);
if (!pi.CanWrite)
    throw new NGPException(StatusCode.TypePropertyNotSetError, propertyName, instanceType.Name);
if (value != null && !value.GetType().IsAssignableFrom(pi.PropertyType))
    value = To(value, pi.PropertyType);
pi.SetValue(instance, value, new object[0]);

// 或者

var count = _unitRepository.ExecuteNonQuery(commandText, parameterCollection);
if (count == 0)
{
    throw new NGPException(StatusCode.DBOperatorError);
}

需要明确指定StatusCode

3.5.14. 使用IUnitRepository时,需要注意:

  • 如果使用了Insert,Update,Delete时,需要在调用结束前显示调用SaveChangesSaveChangesAsync一次

3.6 事务处理

  • 多次使用或者混合使用IUnitRepository以下方法需要额外处理事务,否则涉及DB操作只需要显示调用SaveChangesAsync或者'SaveChanges'

    • Batch开头的方法

    • Bulk开头的方法

  • 暂未提供针对IAdoRepository实例操作事务的封装

  • 事务处理应该遵循最小化原则,即事务内的操作都是关联的。如果只是数据查询的初始化是不需要包含在事务内的

  • 框架不提供事务特性,事务都是显示按业务添加

  • 框架不支持TransactionScope环境事务,改用原始事务处理,写法应该是如下形式:

var strategy = _unitRepository.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
	var transaction = _unitRepository.Database.BeginTransaction();
	try
	{
	    _unitRepository.BulkInsert(list1);
	    _unitRepository.BulkInsertOrUpdate(list2);
	  await _unitRepository.BatchUpdateAsync(criteria,updateValues,updateColumns);
	
	  _unitRepository.insert(item1);
	  _unitRepository.insert(item2);
	  _unitRepository.SaveChanges();
	  transaction.Commit();
	}
	catch(Exception ex)
	{
	    transaction.Rollback();
	  
	    throw new NGPException(ex, StatusCode.DBException);
	}
});

3.7 业务日志

3.8 数据权限

3.9 后台任务

返回