CRL简介

CRL是一款面向对象的轻量级ORM框架,本着快速开发,使用简便的原则,设计为

  1. 无需关心数据库结构,CRL自动维护创建,即写即用(CRL内部有表结构检查机制,保证表结构一致性)
  2. 无需第三方工具生成代理类,标准对象结构即可
  3. 基于Linq.Expression语法解析,完全对象化操作,所有变量参数化处理,无注入安全等问题
  4. 支持join,group等常用语法和函数扩展方法
  5. 多种结果类型返回,对象,自定义对象,泛类型,字典等
  6. 多种数据库,多库支持
  7. 可封装继承的结构,充分使用面向对象的特性

使用CRL快速开发框架有哪些区别?

将此定义为快速开发框架,快速体现在:

  1. 无需关心数据表结构,框架会自动维护,只需要按面向对象的方式定义业务类
  2. 通过面向对象的特性,所有业务类和业务都可以被继承,重用
  3. 数据访问层不存在了,框架内置处理了,支持多种数据库,一些功能可能不支持,如自动编译
  4. 不像传统的三层结构,一些基本增删改查方法不需要写了,这些在业务基类中以泛类型实现过了

还有哪些区别?

  • 自动编译系统(仅MSSQL),上面讲到的的表结构自动同步也属于其中一部份,另外,对于一些复杂的查询,默认都会编译为存储过程,如分页
    对于一个分页查询,如:

    var query = Code.ProductDataManage.Instance.GetLambdaQuery();
    query.Where(b => b.Id > );
    query.Join<Code.Member>((a, b) => a.UserId == b.Id).Select((a, b) => new { a.ProductName, b.Name });//筛选返回的字段
    query.Join<Code.Order>((a, b) => a.UserId == b.UserId).Select((a, b) => new { orderid = b.OrderId });//筛选返回的字段
    query.OrderBy(b=>b.BarCode);
    query.Page(,);

    尽管条件再复杂,只要是基于LambdaQuery语法表示,都会编译成等效的存储过程

  • 缓存绑定,CRL能在所有业务类创建缓存,调用非常简单,只是和数据库查询方法不同,如:
    ProductDataManage.Instance.QueryItemFromCache(1);//从缓存查询
    ProductDataManage.Instance.QueryItem(1);//从数据库查询
    并且.缓存是自动维护,过期后后台线程自动更新,在相同应用程序下,调用Update方法时,也会更新对应的缓存项
  • 内置大数据分库分表解决方案 ,通过CRL的结构,轻松实现此方案
  • 基于为oData查询形式的分布式缓存结构,实现CRL分布式对象缓存
  • CRL.Package业务封装库,对于抽象,可重复使用的业务或组件可通过CRL进行封装重用
    如会员和商家,都继承于CRL.Package.Person.Person
    共同方法,登录,密码修改,验证等方法就统一重用了

最新版由于方法和结构有所更改,升级到3.1

3.1后升级内容

--
版本升级为3.
http://www.cnblogs.com/hubro/p/4981728.html
去掉了业务类里LambdaQuery为参数的查询方法,改为直接由LambdaQuery进行查询返回
返回结果为以下类型
List<dynamic> ToDynamic()
List<TResult> ToList<TResult>()
List<T> ToList()
Dictionary<TKey, TValue> ToDictionary<TKey, TValue>()
筛选值时,能按关联表选择了,GROUP也一样
--
优化分页判断
修改匿名对象查询,使能正确返回值
关联查询改为查询分支了,Join方法会创建一个LambdaQueryJoin对象进行链式调用
--
增加Nullable可空类型属性支持
public DateTime? Birthday
{
get;
set;
}
--
优化表达式动态编译,使常量不再编译成委托
--
优化了关联,使关联后还能关联
--
修改字段别名判断出错
增加测试类TestAll
--
统一函数方法查询语法,增加返回单个字段返回方法GetScalar
--
去掉NOTIN,NOTLIKE扩展方法,扩展方法源类型改为强类型
优化缓存按主键查询方法,直接用键值查询

到目前为止,常用查询语法和函数方法已经解析完成,支持功能表现在:

  • Join 多表N 次关联查询
  • Sum,Count,Max,Min函数统计
  • 表Group,Distinct
  • 查询字段筛选,支持别名
  • 可为空属性类型Nullable
  • 支持虚拟字段
  • 基本逻辑判断语法和扩展函数方法
  • 多表字段排序
  • 多种结果类型返回
  • 任意查询分页

3.1主要优化内容

  1. 优化查询语法,统一了结果返回方法
  2. 增强了表结构检查,后台线程会强制检查对像与表结构一致性

更新1:语法查询优化

语法查询优化表现在以下几个方面

  • 字段间二元运算 
    query.Select(b => new {aa = b.Id * b.Number })//选择字段时二元运算 
    query.Where(b => b.Id < b.Id * b.Number)//条件选择时二元运算
  • 表达式不区分左右
    query.Where(b => 10 > b.Id);和query.Where(b => b.Id < 10 ); 等效
  • 一元运算支持 
    query.Where(b => !b.IsTop)//等效为 isTop!=1 目前只处理了BOOL类型 
    query.Where(b => !b.ProductName.Contains("122"))//BOOL类型的扩展方法同样支持
  • 关联查询支持以上所有特性
    query.Join<Code.Member>((a, b) => a.UserId == b.Id && a.Id == c).Select((a, b) => new { a.BarCode, Year2 = b.Year * b.Id }); 
    关联查询支持关联表排序 query.OrderBy<Code.Member>(b => b.Name, true)
  • 多列排序,只需调用OrderBy方法多次
    query.OrderBy(b => b.Id, true);//按ID倒序
    query.OrderBy(b => b.Name, false)//按Name正序
    结果等效为 order by Id desc,Name asc

查询方法修改

  • 使用LambdaQuery完整查询调用Page方法就可以分页了,通过ToList和ToDynamic方法返回指定类型结果
  • 当设置了关联,Group语法,也会按关联,Group语法解析
  • 当调用了Select方法筛选字段,则需要根据实际情况返回结果类型
  • 返回结果可以有以下几种类型
    • List<dynamic> ToDynamic() 按筛选值返回动态类型
    • List<TResult> ToList<TResult>() 按筛选值返回指定类型
    • List<T> ToList() 直接返回当前类型
    • Dictionary<TKey, TValue> ToDictionary<TKey, TValue>() 按筛选值返回字典(不支持分页)

示例

代码1(实现Group查询)

//Group查询
var query = Code.ProductDataManage.Instance.GetLambdaQuery();
query.Select(b => new { b.BarCode, total = b.BarCode.COUNT() });
query.Where(b => b.Id > 0);
query.GroupBy(b => new { b.BarCode });
query.OrderBy(b => b.BarCode.COUNT(), true);//Group需要设置排序
query.Page(15,1);//如果要分页,设定分页参数就行了
var list = query.ToDynamic();
int total = query.RowCount;

输出

select  t1.BarCode,COUNT(t1.BarCode) as total  from [ProductData] t1  with(nolock)    where (t1.Id>@parame0) group by t1.BarCode  order by  COUNT(t1.BarCode) desc
[parame0]:[0]

代码2(实现关联查询)

//关联查询
var query = Code.ProductDataManage.Instance.GetLambdaQuery();
query.Where(b => b.Id > 0);
query.Join<Code.Member>((a, b) => a.UserId == b.Id).Select((a, b) => new { a.BarCode, b.Name });
query.Page(15,1);//如果要分页,设定分页参数就行了
var list = query.ToDynamic();
int total = query.RowCount;

输出

select  t1.BarCode,t2.Name  from [ProductData] t1  with(nolock)   Inner join Member t2   with(nolock) on (t1.UserId=t2.Id)  where (t1.Id>@parame0)
[parame0]:[0]

代码3(实现关联再Group)

//关联再Group查询
var query = Code.ProductDataManage.Instance.GetLambdaQuery();
query.Where(b => b.Id > 0);
query.Join<Code.Member>((a, b) => a.UserId == b.Id).GroupBy((a, b) => new { a.BarCode, b.Name }).Select((a, b) => new { a.BarCode, b.Name });
query.OrderBy(b=>b.BarCode);
query.Page(15,1);//如果要分页,设定分页参数就行了
var list = query.ToDynamic();
int total = query.RowCount;

输出

select  t1.BarCode,t2.Name  from [ProductData] t1  with(nolock)   Inner join Member t2   with(nolock) on (t1.UserId=t2.Id)  where (t1.Id>@parame0) group by t1.BarCode,t2.Name  order by  t1.BarCode desc
[parame0]:[0]

代码4(实现多次关联)

//多表关联查询
var query = Code.ProductDataManage.Instance.GetLambdaQuery();
query.Where(b => b.Id > 0);
query.Join<Code.Member>((a, b) => a.UserId == b.Id).Select((a, b) => new { a.ProductName, b.Name });//筛选返回的字段
query.Join<Code.Order>((a, b) => a.UserId == b.UserId).Select((a, b) => new { orderid = b.OrderId });//筛选返回的字段
query.OrderBy(b=>b.BarCode);
query.Page(15,1);//如果要分页,设定分页参数就行了
var list = query.ToDynamic();
int total = query.RowCount;

输出

select  t1.ProductName,t2.Name,t3.OrderId as orderid  from [ProductData] t1  with(nolock)   Inner join Member t2   with(nolock) on (t1.UserId=t2.Id)  Inner join OrderProduct t3   with(nolock) on (t1.UserId=t3.UserId)  where (t1.Id>@parame0)  order by  t1.BarCode desc
[parame0]:[0]
  • 对于一个查询,只需调用query.Page()方法就能轻易实现分页
  • 如果需要把动态类型结果转换成定义好的对象,只需调用query.ToList<ClassName>()方法
  • 业务类中不再提供使用完整LambdaQuery作为参数的方法返回数据,而直接使用LambdaQuery的子方法返回数据,如上所示

关于分页

  • 设定分页参数后,CRL会生成对应数据库分页语法,如MSSQL采用ROWNUM分页
  • 分页默认是编译为存储过程,如果数据库不支持自动编译,由以语句的形式查询
  • 默认分页和Group分页为两种处理方式

更新2:表结构强制检查

关于数据表创建缓存依赖

  1. CRL会自动创建对象对应的表结构,并初始
  2. CRL判断该不该创建对象对应的数据表,是由表缓存文件来判断,缓存文件路径/config/TableCache.config
  3. 系统运行时检查目录内有没有缓存,有则加载,没有则创建,在CRL内部检测表创建方法内,根据此缓存来判断,不存在表缓存,则创建表并保存缓存值
  4. 新增的对象,此时缓存内是没有的,则会创建数据表
  5. 在缓存结构和数据表结构一致的情况下,新增对象属性时,会自动创建数据表列
  6. 缓存文件和数据库实际表结构在一些情况下可能不一致,则需要手动干预
  • 当数据库有表,但字段不全,也没有缓存文件,CRL创建缓存文件时会按对象完整的结构缓存,此时缓存的表结构和数据库结构就不一致
  • 当缓存内有表,数据库没有表,CRL没法判断,不会自动创建表
  • 当缓存内表有所有表字段结构,数据库表字段被手动删掉,此时结构不一致
  • 当缓存文件被其它数据源生成的缓存文件覆盖了,可能产生结构不一致

由于以上问题,可能会导至找不到字段或表的错误,当前版本作了完善,于是在后台单独开启了一个线程,用以检查表结构,在对象被首次访问后,就会添加到结构检查队列,由后台异步进行处理

在程序运行后,每个被访问过的对象会被检查一次结构,达到结构同步的目的

3.0增新的演示项目CRLShoppingDemo

之前有人提到看不懂文档,希望有简单的例子,如你所愿,按基本在线销售系统写了一个Demo,以下为运行效果

此演示项目正如上面所说,采用了精简的写法实现了这些业务

继承业务封装,实现会员管理

 public class MemberManage : CRL.Package.Person.PersonBusiness<MemberManage, Member>

商家和会员就都有了登录和验证方法,并实现Form认证

public ActionResult Login(Model.Member member)
{
string error;
var a = MemberManage.Instance.CheckPass(member.AccountNo, member.PassWord, out error);
if (!a)
{
ModelState.AddModelError("", error);
return View();
}
var u = MemberManage.Instance.QueryItem(b => b.AccountNo == member.AccountNo);
if (u.Locked)
{
ModelState.AddModelError("", "账号已锁定");
return View();
}
MemberManage.Instance.Login(u, "Member", false);
string returnUrl = Request["returnUrl"];
if (string.IsNullOrEmpty(returnUrl))
{
returnUrl = "/";
}
return Redirect(returnUrl);
}

页面上需要取当前用户,通过Form认证返回统一的Person对象

var user = MemberManage.Instance.CurrentUser;//CRL.Package.Person.Person

类似FindOne,FindList,分页方法不用去傻傻的写很多次了(一般三层结构会把这类方法写N次),已经自动转换好了

var item = ProductManage.Instance.QueryItemFromCache(b => b.Id == id);//从缓存查询
var item = ProductManage.Instance.QueryItem(b => b.Id == id);//从数据库查找 //分页

var query = ProductManage.Instance.GetLambdaQuery();
query.Where(b => b.SupplierId == CurrentUser.Id);
int count;
var result = ProductManage.Instance.Page(query, out count);


内置账户交易系统,解决多种类型支付管理问题

可以给N种角色设置N种货币类型,统一进行管理

比如以下是充值现金到会员

public bool Charge(Member member, decimal amount, string remark, TransactionType transactionType, out string error)
{
var account = Transaction.AccountManage.Instance.GetAccountId(member.Id, Model.AccountType.会员, transactionType);
string orderId = DateTime.Now.ToString("yyMMddhhmmssff");
int tradeType = 10001;
var trans = new List<CRL.Package.Account.Transaction>();
var ts = new CRL.Package.Account.Transaction() { AccountId = account, Amount = amount, OperateType = CRL.Package.Account.OperateType.收入, TradeType = tradeType, OutOrderId = orderId, Remark = remark };
trans.Add(ts); bool b = Transaction.TransactionManage.Instance.SubmitTransaction(out error,true, trans.ToArray());//提交流水
return b;
}

确认订单时扣款,同时赠送积分

var accountUser = Transaction.AccountManage.Instance.GetAccount(order.UserId, Model.AccountType.会员, Model.TransactionType.现金);
var accountUser2 = Transaction.AccountManage.Instance.GetAccount(order.UserId, Model.AccountType.会员, Model.TransactionType.积分);
if (accountUser.AvailableBalance < order.TotalAmount)
{
error = "账户余额不足";
return false;
} int tradeType = 1001;
var amount = order.TotalAmount;
var orderId = order.OrderId;
var remark = "订单支付";
var trans = new List<CRL.Package.Account.Transaction>();
//生成会员交易流水
var ts = new CRL.Package.Account.Transaction() { AccountId = accountUser.Id, Amount = amount, OperateType = CRL.Package.Account.OperateType.支出, TradeType = tradeType, OutOrderId = orderId, Remark = remark };
trans.Add(ts);
//赠送积分
var ts3 = new CRL.Package.Account.Transaction() { AccountId = accountUser2.Id, Amount = amount, OperateType = CRL.Package.Account.OperateType.收入, TradeType = tradeType, OutOrderId = orderId, Remark = "赠送积分" };
trans.Add(ts3);
bool b = Transaction.TransactionManage.Instance.SubmitTransaction(out error, trans.ToArray());//提交流水
if(!b)
{
return false;
}

更多详细写法请对照示例和开发文档

增加了测试类WebTest.Code.TestAll.cs

此类演示了所有查询方式,在调用通过的情况下,达到集成测试的结果

public class TestAll
{
public static void TestQuery()
{
var instance = Code.ProductDataManage.Instance;
var query = ProductDataManage.Instance.GetLambdaQuery();
query.Select(b => new { b.InterFaceUser, bb = b.Id * b.Number
});
var year = DateTime.Now.Year;
query.Where(b => b.Year == year);//虚拟字段
#region 扩展方法
query.Where(b => < b.Id);//不再区分左边右边了
query.Where(b => b.Id < b.Number);//直接比较可以解析通过
query.Where(b => b.ProductName.Contains(""));//包含字符串
query.Where(b => !b.ProductName.Contains(""));//不包含字符串
query.Where(b => b.ProductName.In("", ""));//string in
query.Where(b => b.AddTime.Between(DateTime.Now, DateTime.Now));//在时间段内
query.Where(b => b.AddTime.DateDiff(DatePart.dd, DateTime.Now) > );//时间比较
query.Where(b => b.ProductName.Substring(, ) == "");//截取字符串
query.Where(b => b.Id.In(, , ));//in
query.Where(b => !b.Id.In(, , ));//not in
query.Where(b => b.UserId.Equals(Code.ProductChannel.其它));//按值等于,enum等于int
query.Where(b => b.ProductName.StartsWith("abc"));//开头值判断
query.Where(b => b.Id.Between(, ));//数字区间
query.Where(b => b.ProductName.Like(""));// %like%
query.Where(b => b.ProductName.LikeLeft(""));// %like
query.Where(b => b.ProductName.LikeRight(""));// like%
query.Page(, );
var sql1 = query.PrintQuery();
var list = query.ToDynamic();
#endregion #region 关联
//索引值
query = ProductDataManage.Instance.GetLambdaQuery();
query.Join<Code.Member>((a, b) => a.UserId == b.Id && a.BarCode.Contains(""))
.SelectAppendValue(b => b.Mobile).OrderBy(b => b.Id, true);
var list2 = query.ToList();
foreach (var item in list2)
{
var mobile = item["Mobile"];
}
//按筛选值
query = ProductDataManage.Instance.GetLambdaQuery();
query.Join<Code.Member>((a, b) => a.UserId == b.Id && a.BarCode.Contains(""))
.Select((a, b) => new { a.BarCode, b.Name }).Join<Code.Order>((a, b) => a.Id == b.UserId);
query.OrderBy(b => b.Id);
var list3 = query.ToDynamic();
foreach (var item in list3)
{
var barCode = item.BarCode;
}
//关联再关联
query = ProductDataManage.Instance.GetLambdaQuery();
query.Join<Code.Member>((a, b) => a.UserId == b.Id && a.BarCode.Contains(""))
.SelectAppendValue(b => b.Mobile).OrderBy(b => b.Id, true).Join<Code.Order>((a, b) => a.Id == b.UserId);
//按IN查询
query = ProductDataManage.Instance.GetLambdaQuery();
query.In<Code.Member>(b => b.UserId, b => b.Id, (a, b) => a.SupplierId == "" && b.Name == "");
var sql2 = query.PrintQuery();
#endregion #region GROUP
query = Code.ProductDataManage.Instance.GetLambdaQuery();
query.Where(b => b.Id > );
//选择GROUP字段
query.Select(b => new
{
sum2 = b.SUM(x => x.Number * x.Id),//等效为 sum(Number*Id) as sum2
total = b.BarCode.COUNT(),//等效为count(BarCode) as total
sum11 = b.Number.SUM(),//等效为sum(Number) as sum1
b.ProductName,
num1 = b.SUM(x => x.Number * x.Id),
num2 = b.MAX(x => x.Number * x.Id),
num3 = b.MIN(x => x.Number * x.Id),
num4 = b.AVG(x => x.Number * x.Id)
});
//GROUP条件
query.GroupBy(b => new { b.ProductName });
//having
query.GroupHaving(b => b.Number.SUM() >= );
//设置排序
query.OrderBy(b => b.BarCode.Count(), true);//等效为 order by count(BarCode) desc
var list4 = query.ToDynamic();
foreach(var item in list4)
{
var total = item.total;
}
#endregion #region DISTINCT
query = Code.ProductDataManage.Instance.GetLambdaQuery();
query.Where(b => b.Id > );
query.DistinctBy(b => new { b.ProductName });
query.DistinctCount();//表示count Distinct 结果名为Total
var list5 = query.ToDynamic();
foreach (var item in list5)
{
var total = item.Total;
//var name = item.ProductName;
}
#endregion #region 函数
//按条件id>0,合计Number列
var sum = instance.Sum(b => b.Id > , b => b.Number * b.UserId);
//按条件id>0,进行总计
var count = instance.Count(b => b.Id > );
var max = instance.Max(b => b.Id > , b => b.Id);
var min = instance.Min(b => b.Id > , b => b.Id);
//使用语句进行函数查询
query = ProductDataManage.Instance.GetLambdaQuery();
query.Select(b => b.Number.SUM());
decimal sum2 = query.ToScalar();
#endregion
}
public static void TestUpdate()
{
var instance = Code.ProductDataManage.Instance;
#region 更新
//要更新属性集合
CRL.ParameCollection c = new CRL.ParameCollection();
c["ProductName"] = "product1";
Code.ProductDataManage.Instance.Update(b => b.Id == , c);
//按对象差异更新
var p = new Code.ProductData() { Id = };
//手动修改值时,指定修改属性以在Update时识别,分以下几种形式
p.Change(b => b.BarCode);//表示值被更改了
p.Change(b => b.BarCode, "");//通过参数赋值
p.Change(b => b.BarCode == "");//通过表达式赋值
Code.ProductDataManage.Instance.Update(b => b.Id == , p);//指定查询更新 p = Code.ProductDataManage.Instance.QueryItem(b => b.Id > );
p.UserId += ;
Code.ProductDataManage.Instance.Update(p);//按主键更新,主键值是必须的
#endregion #region 缓存更新
var item = Code.ProductDataManage.Instance.QueryItemFromCache();
var guid = Guid.NewGuid().ToString().Substring(,);
item.Change(b => b.SupplierName, guid);
Code.ProductDataManage.Instance.Update(item);
item = Code.ProductDataManage.Instance.QueryItemFromCache();
var item2 = Code.ProductDataManage.Instance.QueryItem();
var a = item.SupplierName == item2.SupplierName && item.SupplierName == guid;
if (!a)
{
throw new Exception("更新缓存失败");
}
#endregion #region 事务
string error;
item = Code.ProductDataManage.Instance.QueryItem(); var result = Code.ProductDataManage.Instance.PackageTrans((out string ex) =>
{
ex = "";
var product = new ProductData();
product.BarCode = "sdfsdf";
product.Number = ;
ProductDataManage.Instance.Add(product);
return false;
}, out error);
if (result)
{
throw new Exception("事务未回滚");
}
#endregion
}
}

项目开源

项目开源地址:https://github.com/hubro-xx/CRL3

以后所有升级更新都会基于此版本库,若重大结构变更则建新的项目

需要交流可入群,群内也不再单独上传源码包,最新源码更新此库即可

源码结构:

CRL3.1=>

  CRLShoppingDemo------------->在线购物示例项目

  Core.Mvc------------------------->MVC简单封装

  CRL------------------------------->CRL主框架

  CRL.Package--------------------->CRL业务封装

  RoleControl---------------------->基于CRL实现的通用权限系统

  WebTest------------------------->开发&测试文档

CRL快速开发框架开源完全转到Github的更多相关文章

  1. 非关系型数据库来了,CRL快速开发框架升级到版本4

    轮子?,我很任性,我要造不一样的轮子,同时支持关系型和非关系型的框架有没有 新版数据查询作了些调整,抽象了LabmdaQueryy和DBExtend,升级到版本4,非关系数据库MongoDB被支持了! ...

  2. CRL快速开发框架系列教程十三(嵌套查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  3. CRL快速开发框架系列教程十二(MongoDB支持)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  4. CRL快速开发框架系列教程十一(大数据分库分表解决方案)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  5. CRL快速开发框架系列教程十(导出对象结构)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  6. CRL快速开发框架系列教程九(导入/导出数据)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. CRL快速开发框架系列教程七(使用事务)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  8. CRL快速开发框架系列教程六(分布式缓存解决方案)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  9. CRL快速开发框架系列教程五(使用缓存)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

随机推荐

  1. 【疯狂造轮子-iOS】JSON转Model系列之二

    [疯狂造轮子-iOS]JSON转Model系列之二 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇<[疯狂造轮子-iOS]JSON转Model系列之一> ...

  2. 【流量劫持】躲避 HSTS 的 HTTPS 劫持

    前言 HSTS 的出现,对 HTTPS 劫持带来莫大的挑战. 不过,HSTS 也不是万能的,它只能解决 SSLStrip 这类劫持方式.但仔细想想,SSLStrip 这种算劫持吗? 劫持 vs 钓鱼 ...

  3. 28个你必须知道的HTML5的新特性,技巧以及技术

    崭新新的页面布局 传统的: HTML5: 1. 新的Doctype 尽管使用<!DOCTYPE html>,即使浏览器不懂这句话也会按照标准模式去渲染 2. Figure元素 用<f ...

  4. 【从零开始学BPM,Day2】默认表单开发

    [课程主题]主题:5天,一起从零开始学习BPM[课程形式]1.为期5天的短任务学习2.每天观看一个视频,视频学习时间自由安排. [第二天课程] Step 1 软件下载:H3 BPM10.0全开放免费下 ...

  5. Mysql - 函数

    Mysql提供的函数是在是太多了, 很多我都见过, 别说用了. 园子里面, 有人弄了一个比较全的. MYSQL函数 我这里会将他写的完全拷贝下来, 中间会插入一些自己项目中使用过的心得 一.数学函数 ...

  6. (转载) RESTful API 设计指南

    作者: 阮一峰 日期: 2014年5月22日 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......). 因此,必须有一种统一的机制 ...

  7. CYQ.Data V5 分布式自动化缓存设计介绍

    前方: 其实完成这个功能之前,我就在思考:是先把想法写了来,和大伙讨论讨论后再实现,还是实现后再写文论述自己的思维. 忽然脑后传来一个声音说:你发文后会进入发呆阶段. 所以还是静下心,让我轻轻地把代码 ...

  8. mono for android学习过程系列教程(4)

    今天要讲的事情是构建安卓程序的UI界面. 首先给大家上点小点心,如图: 上面就是我们界面的设计模块,仔细看中间大块的下方,有一个Source,这就类似webform里面的设计和源代码界面. 在这个页面 ...

  9. node(ActiveMq)

    简单尝试了node下的ActiveMQ 1.下载apache-activemq-5.9.0,执行bat文件: 2.登录http://localhost:8161/admin可查看其管理后台: 3.安装 ...

  10. Vue.js——60分钟browserify项目模板快速入门

    概述 在之前的一系列vue.js文章,我们都是用传统模式引用vue.js以及其他的js文件的,这在开发时会产生一些问题. 首先,这限定了我们的开发模式是基于页面的,而不是基于组件的,组件的所有代码都直 ...