前言
我在部落格園潛水兩三年了,在這裡看過很多大神的文章,也學到了很多東西。可以說我是汲取着部落格園的營養成長的。
想當年,我也是拿10個G的精神糧食從一個部落格園大神那裡換來一套開發架構,正式走上開發之路,到後來成為主力開發,再到項目經理再後來順利拿下美工妹,也算是走上人生巅峰。
隻索取,不分享就是自私,大家都這麼自私還怎麼做技術交流,說到分享首先想到的就是我那120G的精神糧食,但是分享這個好像有點法律風險,是以我把這幾年在.net開發生涯中積累的一套架構分享給大家。
早上發過一篇部落格,一會兒就讓管理者拿掉了,這裡我解釋下完全沒有廣告推廣的意思,我不會放置任何推廣資訊,沒那個必要,房子、車子、妹子都有了,在一家還不錯的機關上着班,不然也沒這個閑心來做什麼開源架構,目的是有,就是出來在新手面前裝個逼。這樣吧大家下了代碼去看,裡面如果有一點點廣告嫌疑作者我小JJ自動縮短一厘米。
廢話少說,先來介紹下這個開發架構。
架構名稱:NFine.Framwork,牛逼架構,好架構
架構使用場景:OA、ERP、BPM、CRM、WMS、TMS、MIS等業務管理系統及背景系統
架構解決方案:

解決方案簡介:
1、NFine.Code 底層核心類(開發時不涉及,可編繹成dll提供)。
2、NFine.Data 資料層(開發時不涉及,可編繹成dll提供)。
3、NFine.Application 應用(有點類似業務邏輯層)
4、NFine.Domain 領域層。
5、NFine.Mapping 資料庫映射。
6、NFine.Repository 資料通路。
7、NFine.Web 前端視圖及控制器。
架構主要運用技術:
- 1、前端技術
- JS架構:jquery-2.1.1、Bootstrap.js、JQuery UI
- CSS架構:Bootstrap v3.3.4(穩定是背景,UI方面根據需求自己更新改造吧)。
- 用戶端驗證:jQuery Validation Plugin 1.9.0。
- 線上編輯器:ckeditor、simditor
- 上傳檔案:Uploadify v3.2.1
- 動态頁簽:Jerichotab(自己改造)
- 資料表格:jqGrid、Bootstrap Talbe
- 對話框:layer-v2.3
- 下拉選擇框:jQuery Select2
- 樹結構控件:jQuery zTree、jQuery wdtree
- 頁面布局:jquery.layout.js 1.4.4
- 圖表插件:echarts、highcharts
- 日期控件: My97DatePicker
- 2、後端技術
- 核心架構:ASP.NET MVC5、WEB API
- 持久層架構:EntityFramework 6.0
- 定時計劃任務:Quartz.Net元件
- 安全支援:過濾器、Sql注入、請求僞造
- 服務端驗證:實體模型驗證、自己封裝Validator
- 緩存架構:微軟自帶Cache、Redis
- 日志管理:Log4net、登入日志、記錄檔
- 工具類:NPOI、Newtonsoft.Json、驗證碼、豐富公共類似
架構代碼風格:
資料庫、倉庫代碼
1 using NFine.Code;
2 using System;
3 using System.Collections.Generic;
4 using System.Data.Common;
5 using System.Linq;
6 using System.Linq.Expressions;
7
8 namespace NFine.Data
9 {
10 /// <summary>
11 /// 倉儲接口
12 /// </summary>
13 /// <typeparam name="TEntity">實體類型</typeparam>
14 public interface IRepositoryBase<TEntity> where TEntity : class,new()
15 {
16 int Insert(TEntity entity);
17 int Insert(List<TEntity> entitys);
18 int Update(TEntity entity);
19 int Delete(TEntity entity);
20 int Delete(Expression<Func<TEntity, bool>> predicate);
21 TEntity FindEntity(object keyValue);
22 TEntity FindEntity(Expression<Func<TEntity, bool>> predicate);
23 IQueryable<TEntity> IQueryable();
24 IQueryable<TEntity> IQueryable(Expression<Func<TEntity, bool>> predicate);
25 List<TEntity> FindList(string strSql);
26 List<TEntity> FindList(string strSql, DbParameter[] dbParameter);
27 List<TEntity> FindList(Pagination pagination);
28 List<TEntity> FindList(Expression<Func<TEntity, bool>> predicate, Pagination pagination);
29 }
30 }
using NFine.Code;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;
namespace NFine.Data
{
/// <summary>
/// 倉儲實作
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public class RepositoryBase<TEntity> : IRepositoryBase<TEntity> where TEntity : class,new()
{
public NFineDbContext dbcontext = new NFineDbContext();
public int Insert(TEntity entity)
{
dbcontext.Entry<TEntity>(entity).State = EntityState.Added;
return dbcontext.SaveChanges();
}
public int Insert(List<TEntity> entitys)
{
foreach (var entity in entitys)
{
dbcontext.Entry<TEntity>(entity).State = EntityState.Added;
}
return dbcontext.SaveChanges();
}
public int Update(TEntity entity)
{
dbcontext.Set<TEntity>().Attach(entity);
PropertyInfo[] props = entity.GetType().GetProperties();
foreach (PropertyInfo prop in props)
{
if (prop.GetValue(entity, null) != null)
{
if (prop.GetValue(entity, null).ToString() == " ")
dbcontext.Entry(entity).Property(prop.Name).CurrentValue = null;
dbcontext.Entry(entity).Property(prop.Name).IsModified = true;
}
}
return dbcontext.SaveChanges();
}
public int Delete(TEntity entity)
{
dbcontext.Set<TEntity>().Attach(entity);
dbcontext.Entry<TEntity>(entity).State = EntityState.Deleted;
return dbcontext.SaveChanges();
}
public int Delete(Expression<Func<TEntity, bool>> predicate)
{
var entitys = dbcontext.Set<TEntity>().Where(predicate).ToList();
entitys.ForEach(m => dbcontext.Entry<TEntity>(m).State = EntityState.Deleted);
return dbcontext.SaveChanges();
}
public TEntity FindEntity(object keyValue)
{
return dbcontext.Set<TEntity>().Find(keyValue);
}
public TEntity FindEntity(Expression<Func<TEntity, bool>> predicate)
{
return dbcontext.Set<TEntity>().FirstOrDefault(predicate);
}
public IQueryable<TEntity> IQueryable()
{
return dbcontext.Set<TEntity>();
}
public IQueryable<TEntity> IQueryable(Expression<Func<TEntity, bool>> predicate)
{
return dbcontext.Set<TEntity>().Where(predicate);
}
public List<TEntity> FindList(string strSql)
{
return dbcontext.Database.SqlQuery<TEntity>(strSql).ToList<TEntity>();
}
public List<TEntity> FindList(string strSql, DbParameter[] dbParameter)
{
return dbcontext.Database.SqlQuery<TEntity>(strSql, dbParameter).ToList<TEntity>();
}
public List<TEntity> FindList(Pagination pagination)
{
bool isAsc = pagination.sord.ToLower() == "asc" ? true : false;
string[] _order = pagination.sidx.Split(\',\');
MethodCallExpression resultExp = null;
var tempData = dbcontext.Set<TEntity>().AsQueryable();
foreach (string item in _order)
{
string _orderPart = item;
_orderPart = Regex.Replace(_orderPart, @"\s+", " ");
string[] _orderArry = _orderPart.Split(\' \');
string _orderField = _orderArry[0];
bool sort = isAsc;
if (_orderArry.Length == 2)
{
isAsc = _orderArry[1].ToUpper() == "ASC" ? true : false;
}
var parameter = Expression.Parameter(typeof(TEntity), "t");
var property = typeof(TEntity).GetProperty(_orderField);
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);
resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending", new Type[] { typeof(TEntity), property.PropertyType }, tempData.Expression, Expression.Quote(orderByExp));
}
tempData = tempData.Provider.CreateQuery<TEntity>(resultExp);
pagination.records = tempData.Count();
tempData = tempData.Skip<TEntity>(pagination.rows * (pagination.page - 1)).Take<TEntity>(pagination.rows).AsQueryable();
return tempData.ToList();
}
public List<TEntity> FindList(Expression<Func<TEntity, bool>> predicate, Pagination pagination)
{
bool isAsc = pagination.sord.ToLower() == "asc" ? true : false;
string[] _order = pagination.sidx.Split(\',\');
MethodCallExpression resultExp = null;
var tempData = dbcontext.Set<TEntity>().Where(predicate);
foreach (string item in _order)
{
string _orderPart = item;
_orderPart = Regex.Replace(_orderPart, @"\s+", " ");
string[] _orderArry = _orderPart.Split(\' \');
string _orderField = _orderArry[0];
bool sort = isAsc;
if (_orderArry.Length == 2)
{
isAsc = _orderArry[1].ToUpper() == "ASC" ? true : false;
}
var parameter = Expression.Parameter(typeof(TEntity), "t");
var property = typeof(TEntity).GetProperty(_orderField);
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);
resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending", new Type[] { typeof(TEntity), property.PropertyType }, tempData.Expression, Expression.Quote(orderByExp));
}
tempData = tempData.Provider.CreateQuery<TEntity>(resultExp);
pagination.records = tempData.Count();
tempData = tempData.Skip<TEntity>(pagination.rows * (pagination.page - 1)).Take<TEntity>(pagination.rows).AsQueryable();
return tempData.ToList();
}
}
}
自動映射對象實體
架構界面展示:
支援多皮膚切換
下一篇給大家講解下如何實作動态皮膚切換
總結:
1:本文并沒有詳細講解實作機制。
2:本文并沒有詳細講解開發方式。
但,至少你可以:看源碼、看API、看Demo,還可以加入技術交流群進行交流分享。
當然,後續我會補充相關文章,更加細化和完善的機制及開發方式。
如果您支援開源精神,在精神層面可以點贊以示鼓勵
另外補充:有Bug及漏洞,請私下送出
架構開源位址:
1、源碼下載下傳位址:http://download.csdn.net/detail/nfine_2016/9608074