开源依旧:再次分享一个进销存系统
開篇
我之前發(fā)過一篇博文《兩天完成一個小型工程報價系統(tǒng)(三層架構(gòu))》,不少朋友向我要源碼學(xué)習(xí),后來久而久之忘記回復(fù)了。今天我再分享一個進(jìn)銷存系統(tǒng),只為學(xué)習(xí),沒有復(fù)雜的框架和設(shè)計模式,有的是我個人的理解,大家互相探討技術(shù)才會提高。當(dāng)然我的命名不是很規(guī)范,兄弟們湊合著看。:)
思想和架構(gòu)
在傳統(tǒng)的三層架構(gòu)思想上擴展出N層架構(gòu),將業(yè)務(wù)邏輯層換成WCF服務(wù)。抽象工廠的引入提高了程序的擴展性,單利+緩存+反射則提升了程序的性能。數(shù)據(jù)庫則換成了Oracle,所以相應(yīng)的數(shù)據(jù)訪問層也換成了OracleDal,當(dāng)然你完全可以寫SqlServerDal,因為我數(shù)據(jù)訪問層接口都已定義好。
?
界面和控件的設(shè)計美化
總體思路和流程---數(shù)據(jù)庫Oracle
數(shù)據(jù)庫既然選擇了Oracle,當(dāng)然先必須安裝好Oracle,然后再裝Plsql,這一步也是很簡單的。不清楚的話,可去查找資料。
對Oracle而言,數(shù)據(jù)庫已服務(wù)形式存在,有幾個數(shù)據(jù)庫就對應(yīng)幾個服務(wù),刪除了數(shù)據(jù)庫后相應(yīng)的服務(wù)也沒了,其次一個兼容程序監(jiān)聽著服務(wù)。這些都可以自行配置,我不啰嗦了,畢竟我也不熟。我把Oracle腳本導(dǎo)出了,大家只要復(fù)制到Commad Window里粘貼即可,但前期創(chuàng)建表空間和用戶我還是稍微提一下:
- 首先用你用plsql連接一個服務(wù)(數(shù)據(jù)庫Orcl),用Connect as SysDBA進(jìn)入。
- 創(chuàng)建表空間:注意路徑一定要已經(jīng)存在。
create tablespace invoicing logging datafile 'C:\oracle\product\10.2.0\db_1\oradata\invoicing.dbf' size 32M autoextend on next 32M maxsize 1024M EXTENT MANAGEMENT LOCAL;?
- 找到左下角側(cè)用戶(Users),創(chuàng)建用戶Invoicing,密碼:Invoicing,分配權(quán)限:dba,connect
- 用新創(chuàng)建的用戶名和密碼重新登錄。
- 找到Command Window,把我提供給你的腳本復(fù)制進(jìn)去就OK了。
?
總體思路和流程---數(shù)據(jù)訪問層IDAL
- 一個通用的泛型接口:
public interface IBaseService<T> where T :class{List<T> GetEntities(string sqlWhere);T GetOneEntityByID(int id);T AddEntity(T entity);bool UpdateEntity(T entity);bool DeleteEntity(string sqlWhere);}
- 某個數(shù)據(jù)訪問層接口實繼承這個泛型接口
public interface ICommodityService:IBaseService<Model.CommodityModel>{}
總體思路和流程---抽象工廠Abstract
-
public abstract class DalFactory{public abstract IDAL.ICommodityService CommdityDal{get;}public abstract IDAL.IPurchaseCommodityService PurchaseCommdityDal{get;}public abstract IDAL.IPurchaseOrdersService PurchaseOrderDal{get;}public abstract IDAL.ISalesCommodityService SalesCommodityDal{get;}public abstract IDAL.ISalesOrdersService SalesOrderDal{get;}public abstract IDAL.IUserService UserDal{get;}}
總體思路和流程---數(shù)據(jù)訪問層Dal
- 為了提高效率,可以考慮緩存
public override IDAL.ICommodityService CommdityDal{//緩存里拿get {OracleDAL.CommodityService instance = System.Web.HttpRuntime.Cache["CommodityDal"] as OracleDAL.CommodityService;if (instance == null){instance = new OracleDAL.CommodityService();System.Web.HttpRuntime.Cache.Add("CommodityDal", instance, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);}return instance;}}
?
- OracleHelper和System.Data.OracleClient來實現(xiàn)數(shù)據(jù)訪問層
namespace Insigma.Eyes.PSS.OracleDAL {public class CommodityService:ICommodityService{public List<Model.CommodityModel> GetEntities(string sqlWhere){string sql = string.Format("select * from commodity where 1=1 {0}",sqlWhere);List<Model.CommodityModel> listCommodities = new List<Model.CommodityModel>();//Using 限定對象使用的范圍在花括號里面,出了花括號后釋放資源using (OracleDataReader odr=OracleHelper.ExecuteReader(OracleHelper.ConnectionString, CommandType.Text, sql, null)){while (odr.Read()){Model.CommodityModel commodity = new Model.CommodityModel();commodity.ID = odr.GetInt32(0);commodity.Name = odr.IsDBNull(1) ? "" : odr.GetString(1);commodity.Type = odr.IsDBNull(2) ? "" : odr.GetString(2);commodity.Manufacturer = odr.IsDBNull(3) ? "" : odr.GetString(3);commodity.Inventory = odr.IsDBNull(4) ? 0 : odr.GetInt32(4);commodity.UnitPrice = odr.IsDBNull(5) ? 0 : odr.GetDecimal(5);commodity.Unit = odr.IsDBNull(6) ? "" : odr.GetString(6);listCommodities.Add(commodity);}}return listCommodities;}public Model.CommodityModel GetOneEntityByID(int id){string sqlWhere = string.Format(" and id={0}",id);List<Model.CommodityModel> list = GetEntities(sqlWhere);return list.SingleOrDefault(c => c.ID == id); }private int GetNewID(){string sql = "select s_commodity.nextval from dual";return int.Parse(OracleHelper.ExecuteScalar(OracleHelper.ConnectionString,CommandType.Text,sql,null).ToString());}public Model.CommodityModel AddEntity(Model.CommodityModel entity){entity.ID = GetNewID();string sql = string.Format(@"insert into Commodity(ID,Name,Type,Manufacturer,Inventory,UnitPrice,Unit) values({0},'{1}','{2}','{3}',{4},{5},'{6}')", entity.ID, entity.Name, entity.Type, entity.Manufacturer, entity.Inventory, entity.UnitPrice, entity.UnitPrice);if (OracleHelper.ExecuteNonQuery(OracleHelper.ConnectionString,CommandType.Text,sql,null)>0){return entity;}else{return null;}}public bool UpdateEntity(Model.CommodityModel entity){string sql = string.Format("update Commodity set Name='{0}',Type='{1}',Manufacturer='{2}',Inventory={3},UnitPrice={4},Unit='{5}' where ID={6}",entity.Name, entity.Type, entity.Manufacturer, entity.Inventory, entity.UnitPrice, entity.Unit, entity.ID);return OracleHelper.ExecuteNonQuery(OracleHelper.ConnectionString,CommandType.Text,sql,null)>0; }public bool DeleteEntity(string sqlWhere){string sql = string.Format("delete form Commodity where 1=1 {0}",sqlWhere);return OracleHelper.ExecuteNonQuery(OracleHelper.ConnectionString, CommandType.Text, sql, null) > 0;}} }
總體思路和流程---業(yè)務(wù)邏輯層WCF
- wcf是什么,最簡單理解就是接口,契約,當(dāng)然你可以更加深入研究。我學(xué)的也不深。
namespace Insigma.Eyes.PSS.BLLWCFService {// 注意: 使用“重構(gòu)”菜單上的“重命名”命令,可以同時更改代碼和配置文件中的接口名“ICommodityManagerService”。 [ServiceContract]public interface ICommodityManagerService{[OperationContract][FaultContract(typeof(Exception))]CommodityModel[] GetCommodities(string name,string type,string manufacturer,string priceLow,string priceHigh);[OperationContract]CommodityModel[] GetCommoditiesByCondition(string condition);[OperationContract]CommodityModel GetOneCommodity(int id);[OperationContract][FaultContract(typeof(Exception))]CommodityModel AddCommodity(CommodityModel oneCommodity);[OperationContract][FaultContract(typeof(Exception))]bool UpdateCommodity(Model.CommodityModel commodity);} }
- 實現(xiàn)上面定義的接口契約:
public class PurchaseManagerService : IPurchaseManagerService{// private AbstractFactory.DalFactory dataFactory = null;public PurchaseManagerService(){dataFactory = DefaultProviderDal.DefaultDataProviderFactory;}public Model.PurchaseOrdersModel[] GetPurchaseOrders(string orderNumber, string orderDateStart, string orderDateEnd, string status){string sqlWhere = "";if (!string.IsNullOrWhiteSpace(orderNumber)){sqlWhere += string.Format(" and orderNumber like '%{0}%'", orderNumber);}if (!string.IsNullOrWhiteSpace(orderDateStart)){try{DateTime dt = DateTime.Parse(orderDateStart);sqlWhere += string.Format(" and orderDate>=to_date('{0}','yyyy-MM-dd')", dt.ToString("yyyy-MM-dd"));}catch{Exception oe = new Exception();throw new FaultException<Exception>(oe, "查詢條件開始時間有誤!");}}if (!string.IsNullOrWhiteSpace(orderDateEnd)){try{DateTime dt = DateTime.Parse(orderDateEnd);sqlWhere += string.Format(" and orderDate<=to_date('{0}','yyyy-MM-dd')", dt.ToString("yyyy-MM-dd"));}catch{Exception oe = new Exception();throw new FaultException<Exception>(oe, "查詢條件截至?xí)r間有誤!");}}if (!string.IsNullOrWhiteSpace(status)){sqlWhere += string.Format(" and Status='{0}'", status);}//IDAL.IPurchaseOrdersService purchaseOrdersService = new OracleDAL.PurchaseOrderService();//return purchaseOrdersService.GetEntities(sqlWhere).ToArray();return dataFactory.PurchaseOrderDal.GetEntities(sqlWhere).ToArray();}public Model.PurchaseCommodityModel[] GetPurchaseCommoditiesByID(int purchaseID){string sqlWhere = string.Format(" and PurchaseOrderID={0}",purchaseID);//看看數(shù)據(jù)庫里面的字段//IDAL.IPurchaseCommodityService purchaseCommodityService =new OracleDAL.PurchaseCommodityService();//return purchaseCommodityService.GetEntities(sqlWhere).ToArray();return dataFactory.PurchaseCommdityDal.GetEntities(sqlWhere).ToArray();}public Model.PurchaseCommodityModel AddPurchaseCommodityModel(Model.PurchaseCommodityModel onePurchaseCommodity){//return new OracleDAL.PurchaseCommodityService().AddEntity(onePurchaseCommodity);return dataFactory.PurchaseCommdityDal.AddEntity(onePurchaseCommodity);}//幾個ID要分清楚public bool PostPurchaseOrder(int id){Model.PurchaseOrdersModel oneOrder=GetOnePurchaseOrder(id);if (oneOrder.Status.Equals("已入庫")){Exception oe = new Exception();throw new FaultException<Exception>(oe,"訂單已經(jīng)提交,請務(wù)重復(fù)提交");}List<Model.PurchaseCommodityModel> purchaseCommoditiesList = GetPurchaseCommoditiesByID(id).ToList();IDAL.ICommodityService commodityService = new OracleDAL.CommodityService();foreach (Model.PurchaseCommodityModel onePurchaseCommodity in purchaseCommoditiesList){Model.CommodityModel commodityModel = new Model.CommodityModel();commodityModel.ID = onePurchaseCommodity.CommodityID;commodityModel.Manufacturer = onePurchaseCommodity.CommodityManufacturer;commodityModel.Name = onePurchaseCommodity.CommodityName;commodityModel.Type = onePurchaseCommodity.CommodityType;commodityModel.Unit = onePurchaseCommodity.CommodityUnit;commodityModel.UnitPrice = onePurchaseCommodity.CommodityUnitPrice;commodityModel.Inventory = onePurchaseCommodity.CommodityInventory + onePurchaseCommodity.Count;//這兒不會出現(xiàn)異常了吧,否則要回滾 commodityService.UpdateEntity(commodityModel);}oneOrder.Status = "已入庫";return new OracleDAL.PurchaseOrderService().UpdateEntity(oneOrder);}public Model.PurchaseOrdersModel GetOnePurchaseOrder(int id){//return new OracleDAL.PurchaseOrderService().GetOneEntityByID(id);return dataFactory.PurchaseOrderDal.GetOneEntityByID(id);}public Model.PurchaseCommodityModel GetOnePurchaseCommoditiesByID(int purchaseCommodityID){//return new OracleDAL.PurchaseCommodityService().GetOneEntityByID(purchaseCommodityID);return dataFactory.PurchaseCommdityDal.GetOneEntityByID(purchaseCommodityID);}public bool UpdatePurchaseCommodity(Model.PurchaseCommodityModel model){//return new OracleDAL.PurchaseCommodityService().UpdateEntity(model);return dataFactory.PurchaseCommdityDal.UpdateEntity(model);}public bool DeletePurchaseCommodity(int id){string sqlWhere = " and id=" + id;//return new OracleDAL.PurchaseCommodityService().DeleteEntity(sqlWhere);return dataFactory.PurchaseCommdityDal.DeleteEntity(sqlWhere);}public Model.PurchaseOrdersModel AddPurchaseOrder(Model.PurchaseOrdersModel purchaseOrder){//return new OracleDAL.PurchaseOrderService().AddEntity(purchaseOrder);return dataFactory.PurchaseOrderDal.AddEntity(purchaseOrder);}public bool UpdatePurchaseOrder(Model.PurchaseOrdersModel onePurchaseOrder){//return new OracleDAL.PurchaseOrderService().UpdateEntity(onePurchaseOrder);return dataFactory.PurchaseOrderDal.UpdateEntity(onePurchaseOrder);}public bool DeletePurchaseCommoditiesByPurchaseOrderID(int purchaseOrderID){string sqlWhere = " and PurchaseOrderID=" + purchaseOrderID;//調(diào)用另一個模塊,調(diào)用BLL比較好//return new OracleDAL.PurchaseCommodityService().DeleteEntity(sqlWhere);return dataFactory.PurchaseCommdityDal.DeleteEntity(sqlWhere);}public bool DeleteOrderID(int id){string sqlWhere = string.Format(" and id={0}", id);//return new OracleDAL.PurchaseOrderService().DeleteEntity(sqlWhere);return dataFactory.PurchaseOrderDal.DeleteEntity(sqlWhere);}} }
?
-
dataFactory = DefaultProviderDal.DefaultDataProviderFactory;其實是個單利,我只要反射出一次工廠足以。
public class DefaultProviderDal{private static AbstractFactory.DalFactory instance = null;static DefaultProviderDal(){//string filePath = HttpContext.Current.Server.MapPath("~/DataProvider");string filePath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;string dllFileName = System.Configuration.ConfigurationManager.AppSettings["DataProviderDllFile"];string dalFactoryClassName = System.Configuration.ConfigurationManager.AppSettings["DataProviderFactoryName"];System.Reflection.Assembly dll = System.Reflection.Assembly.LoadFile(filePath + "DataProvider\\" + dllFileName);instance = dll.CreateInstance(dalFactoryClassName) as AbstractFactory.DalFactory;}public DefaultProviderDal(){}public static AbstractFactory.DalFactory DefaultDataProviderFactory{get {return instance;}}}
總體思路和流程---UI
- 對WCF而言,實例化對象越多(如CommodityManagerServiceClient類的實例),對服務(wù)器壓力越大,所以也可以考慮單利。
public class WCFServiceBLL{//對WCF而言,對象實例化越多,對服務(wù)器壓力越大。static BLLCommodity.CommodityManagerServiceClient commodityClient;static BLLSalesOrders.SalesManagerServiceClient salesClient;static BLLUsers.UserManagerServiceClient userClient;static BLLPurchaseOrders.PurchaseManagerServiceClient purchaseClient;public static CommodityManagerServiceClient GetCommodityService(){if (commodityClient==null){commodityClient = new CommodityManagerServiceClient();}if (commodityClient.State==CommunicationState.Closed){commodityClient = new CommodityManagerServiceClient();}if (commodityClient.State==CommunicationState.Faulted){commodityClient = new CommodityManagerServiceClient();}return commodityClient;
補充
由于數(shù)據(jù)庫之間的主外鍵關(guān)系以及多表查詢,為了方便,我創(chuàng)建了視圖,這和SqlServer里面是一樣的(Oracle里面是Create Or Replace),當(dāng)然你也可以建立外鍵對象,我上個項目就是這么干的,當(dāng)然ORM我們就不討論了。
?
create or replace view v_purchasecommodity as select pc.id,pc.purchaseorderid,pc.commodityid,c.name CommodityName, c.type commodityType,c.manufacturer CommodityManufacturer,c.inventory CommodityInventory, c.unitprice CommodityUnitPrice,c.unit CommodityUnit,pc.count,pc.purchaseprice,pc.totalprice from purchasecommodity pc inner join commodity c on pc.commodityid = c.id;?
?
再補充一點:Oracle的自動增長列并不是像SqlServer那樣設(shè)置一下,就會自動增長,Oracle里面需要你自己創(chuàng)建Sequences,圖形操作也行,命令也行,我導(dǎo)出的Oracle腳本里面已經(jīng)包含了相應(yīng)的Sequences,應(yīng)該可以看懂的。其余差別不大,相信你能看懂。
?
create sequence INVOICING.S_USERS minvalue 1 maxvalue 999999999999999999999999999 start with 1 increment by 1 cache 20;?
?
?關(guān)于界面美化的一些心得:
Winform程序功能很重要,但能提高用戶體驗?zāi)鞘亲钔昝赖?#xff0c;所以我用了一些圖標(biāo),設(shè)置相應(yīng)的大小,當(dāng)然用戶控件也是很重要的一部分,用戶控件嵌套在窗體里面是很簡單的:
?
public class LoadControls{public static void LoadInventory(Control parent){parent.Controls.Clear();Inventory inventory = new Inventory();inventory.Dock = DockStyle.Fill;parent.Controls.Add(inventory);}public static void LoadPurchase(Control parent){parent.Controls.Clear();Purchase purchase = new Purchase();purchase.Dock = DockStyle.Fill;parent.Controls.Add(purchase);}public static void LoadSales(Control parent){parent.Controls.Clear();Sales sales = new Sales();sales.Dock = DockStyle.Fill;parent.Controls.Add(sales);}?
?
?
?
?
總結(jié)
沒有什么猶豫就寫完了這篇博文,我把源代碼貢獻(xiàn)出來,當(dāng)然這個例子只為學(xué)習(xí),有需要的兄弟們可以拿去參考參考,大家多交流交流,才會相互促進(jìn)進(jìn)步,如果您覺得滿意的話,不放支持我一下,幫忙頂個,有動力才有精力寫出更好的博客,3x:)
?
下載
轉(zhuǎn)載于:https://www.cnblogs.com/OceanEyes/archive/2012/08/03/invoicing.html
總結(jié)
以上是生活随笔為你收集整理的开源依旧:再次分享一个进销存系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《棣华驿见杨八题梦兄弟诗》第四句是什么
- 下一篇: 得到最后的自增长列的最后一个值