nonepassby

导航

CSLA.NET快速入门系列——实现子对象在WcfPorxy模式下的懒加载(LazyLoad)

在一般的业务系统中,父子关系的存在是非常广泛的,如订单和订单明细,部门和职员等。在前面的文章我们介绍了业务对象,命令对象和DataPortal的相关内容。

在CSLA框架中,父子关系是一个很重要的关系,相应的实体对应到业务对象和业务对象集合,并通过父对象的属性成员来使用子对象集合。

在一般应用中,有时只需要对root对象进行操作,而无需对其子对象进行操作,如果在加载root对象时,同时也将其所有子对象加载的话会造成比较差的性能。因此,CSLA框架提出了懒加载(LazyLoad)的概念,即只在需要操作子对象是才加载子对象。

在CSLA框架中,只有Root业务对象才允许直接访问数据源(服务端代码,后端)。因此,所有子对象的对数据源的访问必须通过其Root对象来进行,这样设计有利有弊,好处是开发人员直接利用OO的方式对对象进行操作,只需要一次调用Root对象即可对Root对象及其所有的子对象进行更新;不好的地方是无法直接对子对象数据源操作,同时,由于必须依赖于root对象对数据进行访问,即其无法单独“移动”(见前面DataPortal介绍)。

因此,当在使用WcfProxy模式下使用懒加载时,由于Root对象已经在客户端(前端),那么在加载子对象时,DataPortal运行时也在客户端,在加载时会出现空引用的问题(如数据源的连接),导致程序异常。

知道异常的原因,那么寻找解决方案就比较简单了,只要我们在加载子对象时,让DataPortal运行在后端,那么问题就迎刃而解。而在前面的文章中,我们介绍了命令对象,命令对象刚好已经在服务端执行的命令。因此,要以利用命令对象来解决LazyLoad时的问题。

当然,我们不需要为不同的子对象加载分别创建命令对象,而是可以通过实现一个通用命令对象来完成子对象加载的操作。

创建子对象加载命令对象LazyLoadChildCommand,如下:

 

View Code
[Serializable]
    [Csla.Server.ObjectFactory(FactoryNames.LazyLoadChildCommandFactoryName)]
    public class LazyLoadChildCommand : CommandBase<LazyLoadChildCommand>
    {
        private const BindingFlags factoryFlags = BindingFlags.Static|
            BindingFlags.NonPublic | BindingFlags.Public |
            BindingFlags.FlattenHierarchy;

             #region Authorization Methods

        public static bool CanExecuteCommand()
        {
            return true;
        }

        #endregion
        #region Client-side Code
        internal string MethodName
        {
            get;set;
        }

        internal Type TargetObjectType
        {
            get;
            set;
        }
        internal object[] Parameters { getset; }
        public Object Result { getinternal set; }

        private void BeforeServer(string factoryMethodName, Type targetType, params object[] parameters)
        {
            MethodName = factoryMethodName;
            this.Parameters = parameters;
            this.TargetObjectType = targetType;
            Result = null;
        }

        private void AfterServer()
        {
        }

        
        #endregion
        public static T Execute<T>(string factoryMethodName, params object[] Parameters) where T : class
        {
            if (!CanExecuteCommand())
                throw new System.Security.SecurityException("Not authorized to execute command");

            var cmd = new LazyLoadChildCommand();
            cmd.BeforeServer(factoryMethodName,typeof(T), Parameters);
            cmd = DataPortal.Execute(cmd);
            cmd.AfterServer();

            return (T)cmd.Result;
        }



        public static object CallFactoryMethod(Type objectType, string method, params object[] Parameters)
        {
            object returnValue;
            System.Reflection.MethodInfo factory = objectType.GetMethod(
                 method, factoryFlags, null,
                 MethodCaller.GetParameterTypes(Parameters), null);

            if (factory == null)
            {
               
                int parameterCount = Parameters.Length;
                System.Reflection.MethodInfo[] methods = objectType.GetMethods(factoryFlags);
                foreach (System.Reflection.MethodInfo oneMethod in methods)
                    if (oneMethod.Name == method && oneMethod.GetParameters().Length == parameterCount)
                    {
                        factory = oneMethod;
                        break;
                    }
            }
            if (factory == null)
            {               
                throw new InvalidOperationException(
                  string.Format(Resources.NoSuchFactoryMethod, method));
            }
            try
            {
                returnValue = factory.Invoke(null, Parameters);
            }
            catch (Exception ex)
            {
                Exception inner = null;
                if (ex.InnerException == null)
                    inner = ex;
                else
                    inner = ex.InnerException;
                throw new CallMethodException(factory.Name + " " + Resources.MethodCallFailed, inner);
            }
            return returnValue;
        }

    }

 

静态工厂方法public static T Execute<T>(string factoryMethodName, params object[] Parameters)

  T:为要获取的子业务对象集合

  

  factoryMethodName:为子业务对象集合类业务方法(根据父对象唯一键获取子对象集合的方法,为静态工厂方法)

  Parameters:为factoryMethodName业务方法的参数。

 

最后我们再在父对象的相应子象集合属性get处理:

 

private static readonly PropertyInfo< ScrumProjectReleaseList > _scrumProjectReleasesProperty = RegisterProperty<ScrumProjectReleaseList>(p => p.ScrumProjectReleases, Csla.RelationshipTypes.Child);
        public ScrumProjectReleaseList ScrumProjectReleases
        {
            get
            {
                bool cancel = false;
                OnChildLoading(_scrumProjectReleasesProperty, ref cancel);
    
                if (!cancel)
                {
                    if(!FieldManager.FieldExists(_scrumProjectReleasesProperty))
                    {
                        var criteria = new ScrumRM.Business.ScrumProjectReleaseCriteria {ProjectId = Identification};
                        
    
                        if(!ScrumRM.Business.ScrumProjectReleaseList.Exists(criteria))
                            LoadProperty(_scrumProjectReleasesProperty, ScrumRM.Business.ScrumProjectReleaseList.NewList());
                        else                                                        LoadProperty(_scrumProjectReleasesProperty, LazyLoadChildCommand.Execute<ScrumProjectReleaseList>("GetByProjectId", Identification));
                    }
                }

                return GetProperty(_scrumProjectReleasesProperty);
            }
        }

 

这样,我们就实现了子对象在WcfPorxy模式下的懒加载(LazyLoad)的一种方案。

 

 

posted on 2012-08-01 18:40  jack  阅读(472)  评论(0)    收藏  举报