zoukankan      html  css  js  c++  java
  • Enterprise Solution 管理软件开发框架流程实战

    1 定义模块和功能

    执行系统功能(SAUTSF),在系统主文件(System Master File SAMF)模块中增加功能SAMFEM,Employee Master。

    给有权限的用户组分配功能SAMFEM的权限,包含新增,删除,修改,打印,过帐权限,这是功能权限。

    如果需要增加字段权限,比如可以编辑员工薪资字段,应该修改用户表(User)增加权限字段。

    2 定义导航菜单

    把增加的功能放置到合适的功能菜单中,菜单项的位置根据需要而定。比如员工主文件,可以放置到主档定义中,还可以放置一份到人事管理的设定菜单项中。定义一个菜单项位置,系统会生成三个地方的导航菜单项:标题栏下的主菜单(ToolStrip), 导航树右边的列表视图(ListView),导航图的上下文菜单(ContextMenu),三种方式帮助用户快速查找与执行功能。

    3 设计数据库表

    以员工表为例子,员工表的数据库脚本如下:

    CREATE TABLE [dbo].[Employee]
    (
    [Recnum] [numeric] (18, 0) NOT NULL IDENTITY(1, 1),
    [EmployeeNo] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    [Department] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [ProductionGroup] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [CompanyCode] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [BranchCode] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Name] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    [Account] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Password] [nvarchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Gender] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Birthday] [datetime] NULL,
    [Mobile] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Address] [nvarchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [HomeTelephone] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Post] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Type] [char] (4) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [Suspended] [char] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL CONSTRAINT [DF__tEmployee__Enabl__32CB82C6] DEFAULT ((1)),
    [JobTitle] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [JoinDate] [datetime] NULL,
    [LeftDate] [datetime] NULL,
    [Photo] [image] NULL
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    GO
    ALTER TABLE [dbo].[Employee] WITH NOCHECK ADD CONSTRAINT [CKC_TYPE_TEMPLOYE] CHECK (([Type]=(1) OR [Type]=(0)))
    GO
    ALTER TABLE [dbo].[Employee] ADD CONSTRAINT [PK_TEMPLOYEE] PRIMARY KEY CLUSTERED  ([EmployeeNo]) ON [PRIMARY]
    GO
    ALTER TABLE [dbo].[Employee] WITH NOCHECK ADD CONSTRAINT [FK_Employee_Department] FOREIGN KEY ([Department]) REFERENCES [dbo].[Department] ([DepartmentCode])
    GO
    ALTER TABLE [dbo].[Employee] NOCHECK CONSTRAINT [FK_Employee_Department]
    GO

     

    4 LLBL Gen Pro生成实体映射

    执行程序LLBL Gen Pro,连接到数据库并添加Employee数据表,最后点击生成源代码文件。

    image

    一般情况下用默认的命名规则即可。比如Item_No映射的实体字段名是ItemNo,默认去掉下划线。

    5 实体数据访问接口与实现生成

    用Template目录中的Code Smith模板生成接口与实现类,代码如下:

    数据接口类:

    public interface IEmployeeManager
        {
            EmployeeEntity GetEmployee(System.String EmpNo);
            EmployeeEntity GetEmployee(System.String EmpNo, IPrefetchPath2 prefetchPath);
            EmployeeEntity GetEmployee(System.String EmpNo, IPrefetchPath2 prefetchPath, ExcludeIncludeFieldsList fieldList);
    
            EntityCollection GetEmployeeCollection(IRelationPredicateBucket filterBucket);
            EntityCollection GetEmployeeCollection(IRelationPredicateBucket filterBucket, ISortExpression sortExpression);
            EntityCollection GetEmployeeCollection(IRelationPredicateBucket filterBucket, ISortExpression sortExpression, IPrefetchPath2 prefetchPath);
            EntityCollection GetEmployeeCollection(IRelationPredicateBucket filterBucket, ISortExpression sortExpression, IPrefetchPath2 prefetchPath, ExcludeIncludeFieldsList fieldList);
    
            EmployeeEntity SaveEmployee(EmployeeEntity employee);
            EmployeeEntity SaveEmployee(EmployeeEntity employee, EntityCollection entitiesToDelete);
            EmployeeEntity SaveEmployee(EmployeeEntity employee, EntityCollection entitiesToDelete, string seriesCode);
    
            void DeleteEmployee(EmployeeEntity employee);
    
            bool IsEmployeeExist(System.String EmpNo);
            bool IsEmployeeExist(IRelationPredicateBucket filterBucket);
            int GetEmployeeCount(IRelationPredicateBucket filterBucket);
    
            EmployeeEntity CloneEmployee(System.String EmpNo);
            void PostEmployee(System.String EmpNo);
            void PostEmployee(EmployeeEntity employee);
        }

    数据实现类:

    [RemoteService("EmployeeManager")]                    
    public class EmployeeManager : Foundation.Common.ManagerBase, IEmployeeManager
    {
            public EmployeeEntity GetEmployee(System.String EmpNo)
            {
                IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.EmployeeEntity);
                prefetchPath.Add(EmployeeEntity.PrefetchPathEmployeeTrainings);
                return GetEmployee(EmpNo, prefetchPath);
            }
    
            public EmployeeEntity GetEmployee(System.String EmpNo, IPrefetchPath2 prefetchPath)
            {
                return GetEmployee(EmpNo, prefetchPath, null);
            }
    
            public EmployeeEntity GetEmployee(System.String EmpNo, IPrefetchPath2 prefetchPath, ExcludeIncludeFieldsList fieldList)
            {
                EmployeeEntity employee = new EmployeeEntity(EmpNo);
                using (DataAccessAdapterBase adapter = GetCompanyDataAccessAdapter())
                {
                    bool found = adapter.FetchEntity(employee, prefetchPath, null, fieldList);
                    if (!found) throw new Foundation.Common.RecordNotFoundException("Invalid Employee");
                }
                return employee;
            }
    
            public EntityCollection GetEmployeeCollection(IRelationPredicateBucket filterBucket)
            {
                return GetEmployeeCollection(filterBucket, null);
            }
    
            public EntityCollection GetEmployeeCollection(IRelationPredicateBucket filterBucket, ISortExpression sortExpression)
            {
                return GetEmployeeCollection(filterBucket, sortExpression, null);
            }
    
            public EntityCollection GetEmployeeCollection(IRelationPredicateBucket filterBucket, ISortExpression sortExpression, IPrefetchPath2 prefetchPath)
            {
                return GetEmployeeCollection(filterBucket, sortExpression, prefetchPath, null);
            }
    
            public EntityCollection GetEmployeeCollection(IRelationPredicateBucket filterBucket, ISortExpression sortExpression, IPrefetchPath2 prefetchPath, ExcludeIncludeFieldsList fieldList)
            {
                EntityCollection employeeCollection = new EntityCollection(new EmployeeEntityFactory());
                using (DataAccessAdapterBase adapter = GetCompanyDataAccessAdapter())
                {
                    adapter.FetchEntityCollection(employeeCollection, filterBucket, 0, sortExpression, prefetchPath, fieldList);
                }
                return employeeCollection;
            }
    
    
            public EmployeeEntity SaveEmployee(EmployeeEntity Employee)
            {
                return SaveEmployee(Employee, null);
            }
    
            public EmployeeEntity SaveEmployee(EmployeeEntity Employee, EntityCollection entitiesToDelete)
            {
                return SaveEmployee(Employee, entitiesToDelete, string.Empty);
            }
    
            public EmployeeEntity SaveEmployee(EmployeeEntity Employee, EntityCollection entitiesToDelete, string seriesCode)
            {
                using (DataAccessAdapterBase adapter = GetCompanyDataAccessAdapter())
                {
                    try
                    {
                        adapter.StartTransaction(IsolationLevel.ReadCommitted, "SaveEmployee");
                        adapter.SaveEntity(Employee, true, false);
    
                        IEmployeeTrainingManager trainingManager = ClientProxyFactory.CreateProxyInstance<IEmployeeTrainingManager>();
                        foreach (var employeeTraining in Employee.EmployeeTrainings)
                        {
                            trainingManager.SaveEmployeeTraining(employeeTraining);
                        }
                        adapter.Commit();
                    }
                    catch
                    {
                        adapter.Rollback();
                        throw;
                    }
                }
                return Employee;
            }
    
            public void DeleteEmployee(EmployeeEntity Employee)
            {
                using (DataAccessAdapterBase adapter = GetCompanyDataAccessAdapter())
                {
                    if (!adapter.IsEntityExist<EmployeeEntity>(Employee))
                        return;
    
                    try
                    {
                        adapter.StartTransaction(IsolationLevel.ReadCommitted, "DeleteEmployee");
                        IEmployeeTrainingManager trainingManager = ClientProxyFactory.CreateProxyInstance<IEmployeeTrainingManager>();
                        foreach (var employeeTraining in Employee.EmployeeTrainings)
                        {
                            trainingManager.DeleteEmployeeTraining(employeeTraining);
                        }
                        adapter.DeleteEntity(Employee);
                        adapter.Commit();
                    }
                    catch
                    {
                        adapter.Rollback();
                        throw;
                    }
                }
            }
    
            public bool IsEmployeeExist(System.String EmpNo)
            {
                RelationPredicateBucket filterBucket = new RelationPredicateBucket();
                filterBucket.PredicateExpression.Add(EmployeeFields.EmployeeNo == EmpNo);
                return IsEmployeeExist(filterBucket);
            }
    
            public bool IsEmployeeExist(IRelationPredicateBucket filterBucket)
            {
                return (GetEmployeeCount(filterBucket) > 0);
            }
    
            public int GetEmployeeCount(IRelationPredicateBucket filterBucket)
            {
                using (DataAccessAdapterBase adapter = GetCompanyDataAccessAdapter())
                {
                    return adapter.GetDbCount<EmployeeEntity>(filterBucket);
                }
            }
    
            public EmployeeEntity CloneEmployee(System.String EmpNo)
            {
                EmployeeEntity source = this.GetEmployee(EmpNo);
                EmployeeEntity employee = (EmployeeEntity)CloneEntity(source);
                return employee;
            }
    
            public void PostEmployee(System.String EmpNo)
            {
                return;
            }
    
            public void PostEmployee(EmployeeEntity Employee)
            {
                return;
            }
    }
     

    6 界面设计,控件数据绑定,查找与钻取

    Windows窗体设计的主要流程步骤

    1)  拖一个EntityCollection组件到界面中,这个组件来自于LLBL Gen Pro生成的数据库映射项目。

    设置EntityFactoryToUse=Kingston.FactoryClasses.EmployeeEntityFactory。

    2)  拖多个BindingSource组件到界面。每一层控件都需要一个BindingSource组件,如果界面是单笔数据操作,还需要拖一个空的BindingSource组件到界面中,并将它设为窗体的NavigatorBindingSource。

    3) 依次绑定控件与数据源组件的属性。要注意选对控件,TextEditor,NumbericEditor。对于必须输入值的控件,要设置Required=true,对于映射到主键字段的控件,要设AutoFind=true。

    4) 给控件增加查找与钻取。

    5) 设置控件的tab index。

    image

    7 验证和计算逻辑

    1) 增加实体属性的默认值。修改文件EmployeeEntity.Implementation.cs

    public partial class EmployeeEntity
    {
                 protected override void OnInitialized()
                 {
                 base.OnInitialized();
    
                      // Assign default value for new entity
                 if (Fields.State == EntityState.New)
                 {
             #region DefaultValue
                    
             // __LLBLGENPRO_USER_CODE_REGION_START DefaultValue
             this.Fields[(int) EmployeeFieldIndex.Suspended].CurrentValue = false;
             // __LLBLGENPRO_USER_CODE_REGION_END
    
               #endregion

    2) 增加自动带值。比如输入员工所在的部门编码,要自动带入部门名称。

    private void OnChangeDepartment(string originalValue)
    {
            IDepartmentManager departmentManager =CreateProxyInstance<IDepartmentManager>();
            if (departmentManager.IsDepartmentExist(Department))
            {
                  ExcludeIncludeFieldsList fieldList = new ExcludeIncludeFieldsList(false);
                  fieldList.Add(DepartmentFields.FullName);
                  DepartmentEntity department = departmentManager.GetDepartment(Department, null, fieldList);
                  this.DepartmentName = department.FullName;
            }
    }
     
     

    3) 增加验证代码,对需要验证的属性值进行验证。

    值验证:

    public override bool ValidateFieldValue(IEntityCore involvedEntity, int fieldIndex, object value)
    {
                bool result = base.ValidateFieldValue(involvedEntity, fieldIndex, value);
    
                if (!result) return false;
                switch ((EmployeeFieldIndex)fieldIndex)
                {              
                     case EmployeeFieldIndex.Department:
                        return ValidateDepartment((string)value, (EmployeeEntity)involvedEntity);
                        break;
    
    private bool ValidateDepartment(string value, EmployeeEntity EGEntity)
    {
           if (!string.IsNullOrWhiteSpace(value))
           {
                 IDepartmentManager departmentManager = CreateProxyInstance<IDepartmentManager>();
                 departmentManager.ValidateDepartment(value);
           }
           return true;
    }

    删除验证:

    public override void ValidateEntityBeforeDelete(IEntityCore involvedEntity)
    {
         base.ValidateEntityBeforeDelete(involvedEntity);
         EmployeeEntity employeeEntity = (EmployeeEntity)involvedEntity;
         ISalesmanManager salesmanManager = CreateProxyInstance<ISalesmanManager>();
             
         RelationPredicateBucket filterBucket = new RelationPredicateBucket();
         filterBucket.PredicateExpression.Add(SalesmanFields.EmployeeNo == employeeEntity.EmployeeNo);
         if (salesmanManager.IsSalesmanExist(filterBucket))
         {
             throw new FieldValidationException("Employee No. already used in salesman");
         }

    保存前验证:

    public override void ValidateEntityBeforeSave(IEntityCore involvedEntity)
    {
          base.ValidateEntityBeforeSave(involvedEntity);
          EmployeeEntity employeeEntity = (EmployeeEntity)involvedEntity;
    
          if (string.IsNullOrWhiteSpace(employeeEntity.EmployeeNo))
          {
               throw new EntityValidationException("Employee No. is required");
          }
     

    8 生成并发布程序

    打开Visual Studio 2015或用MSBUILD生成程序。

    image

    执行.NET Reactor批处理脚本,将生成的文件复制到客户的更新服务器中。

  • 相关阅读:
    鼠标拖拽窗口效果(不允许拖出屏幕的可视区域)
    react-context
    上下固定,中间自适应布局
    左右固定,中间自适应布局
    leetcode每日一题(2020-07-03):108. 将有序数组转换为二叉搜索树
    leetcode每日一题(2020-07-02):378. 有序矩阵中第K小的元素
    leetcode每日一题(2020-07-01):718. 最长重复子数组
    leetcode每日一题(2020-06-30):剑指 Offer 09. 用两个栈实现队列
    leetcode每日一题(2020-06-29):215. 数组中的第K个最大元素
    leetcode每日一题(2020-06-28):209. 长度最小的子数组
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/4719897.html
Copyright © 2011-2022 走看看