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. UniqueIdentifier 数据类型 和 GUID 生成函数

    UniqueIdentifier 数据类型用于存储GUID的值,占用16Byte. SQL Server将UniqueIdentifier存储为16字节的二进制数值,Binary(16),按照特定的格 ...

  2. 开始学nodejs——net模块

    net模块的组成部分 详见 http://nodejs.cn/api/net.html 下面整理出了整个net模块的知识结构,和各个事件.方法.属性的用法 net.Server类 net.Socket ...

  3. node中子进程同步输出

    管道 通过"child_process"模块fork出来的子进程都是返回一个ChildProcess对象实例,ChildProcess类比较特殊无法手动创建该对象实例,只能使用fo ...

  4. CSS 3学习——box-sizing和背景

    box-sizing 在CSS 2中设置元素的width和height仅仅是设置了元素内容区的宽和高,元素实际的尺寸是margin + border + padding + 内容区. CSS 3(截止 ...

  5. 代码的坏味道(22)——不完美的库类(Incomplete Library Class)

    坏味道--不完美的库类(Incomplete Library Class) 特征 当一个类库已经不能满足实际需要时,你就不得不改变这个库(如果这个库是只读的,那就没辙了). 问题原因 许多编程技术都建 ...

  6. org.jboss.deployment.DeploymentException: Trying to install an already registered mbean: jboss.jca:service=LocalTxCM,name=egmasDS

    17:34:37,235 INFO [Http11Protocol] Starting Coyote HTTP/1.1 on http-0.0.0.0-8080 17:34:37,281 INFO [ ...

  7. C# 工厂模式+虚方法(接口、抽象方法)实现多态

    面向对象语言的三大特征之一就是多态,听起来多态比较抽象,简而言之就是同一行为针对不同对象得到不同的结果,同一对象,在不同的环境下得到不同的状态. 实例说明: 业务需求:实现一个打开文件的控制台程序的d ...

  8. 【SAP业务模式】之ICS(二):基础数据

    讲完业务,计划在前台做一下ICS的基本操作,不过在操作之前,得先建立好基本的基础数据. 1.首先创建接单公司LEON,对应工厂是ADA: 2.创建生产公司MXPL,对应工厂是PL01: 3.创建接单公 ...

  9. Android Studio分类整理res/Layout中的布局文件(创建子目录)

    res/layout中的布局文件太杂,没有层次感,受不了的我治好想办法解决这个问题. 前几天看博客说可以使用插件分组,可惜我没找到.知道看到另一篇博客时,才知道这个方法不能用了. 不能用插件,那就手动 ...

  10. charles工具抓包教程(http跟https)

    1.下载charles 可以去charles官网下载,下载地址:http://www.charlesproxy.com/download/    根据自己的操作系统下载对应的版本,然后进行安装,然后打 ...