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.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.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 = 203.3.2. 索引字段的参数化查询
错误:
select id from t where num = @num正确:
Select id from t with(index(索引名)) where num = @num3.3.3. 不要在where字句中对字段进行表达式操作
错误:
Select id from t where num/2 = 100正确:
Select id from t where num = 2003.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.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. 不要使用ArrayList和HashTable
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.1. 控制器必须继承:BaseApiController
3.5.2. 控制器的Action必须是Post
3.5.3. 控制的的Action返回必须调用基类的Ok,OkDataResult或OkPageDataResult
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配置,并且继承Profile和INGPMapperProfile
/// <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时,需要在调用结束前显示调用SaveChanges或SaveChangesAsync一次
-
多次使用或者混合使用
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);
}
});