Asp.net MVC 示例项目"Suteki.Shop"分析之---Model和Service

  在Suteki.Shop中Model的原型是基于Linq to SQL创建的,其dbml文件位于Suteki.Shop\Shop.dbml。而Suteki.Shop在此文件的基本上,以"partial class "的方式在Suteki.Shop\Model文件夹下创建了相应的类文件以扩展Shop.dbml中Model类的一些方法和属性声明,如下图:
 
         
    
       为了便于大家理解,下面以Model中的Product.cs为例进行说明。
    
        Product是对网站中所销售商品的数据信息类。在其中定义了一些属性(声明在Shop.dbml中):
 
   private   int  _ProductId;   // 产品ID
   private   int  _CategoryId;     // 产品所属分类ID
   private   string  _Name;   // 产品名称
   private   string  _Description; // 产品描述  
   private   decimal  _Price;   // 产品价格
   private   int  _Position;   // 在列表中的位置
   private   int  _Weight;   // 重量
   private   bool  _IsActive;   // 当前是否激活显示
   private   string  _UrlName;     // 产品的URL链接
    
         而Product.cs这个文件其实是以partial方式对Shop.dbml中的Product类的"扩展",下面是其实现代码:
 
public   partial   class  Product : IOrderable, IActivatable, IUrlNamed
{
     partial   void  OnNameChanging( string  value)
    {
        value.Label( " Name " ).IsRequired();
    }

     partial   void  OnNameChanged()
    {
        UrlName  =  Name.ToUrlFriendly();
    }

     partial   void  OnDescriptionChanging( string  value)
    {
        value.Label( " Description " ).IsRequired();
    }

     public   bool  HasMainImage
    {
         get
        {
             return   this .ProductImages.Count  >   0 ;
        }
    }

     public  Image MainImage
    {
         get
        {
             if  (HasMainImage)  return   this .ProductImages.InOrder().First().Image;
             return   null ;
        }
    }

     public   bool  HasSize
    {
         get
        {
             return   this .Sizes.Active().Count()  >   0 ;
        }
    }

     public  Size DefaultSize
    {
         get
        {
             if  ( this .Sizes.Count()  ==   0throw   new  ApplicationException( " Product has no default size " );
             return   this .Sizes[ 0 ];
        }
    }

     public   string  IsActiveAsString
    {
         get
        {
             if  (IsActive)  return   string .Empty;
             return   "  Not Active " ;
        }
    }

  public   static  Product DefaultProduct( int  parentCategory,  int  position)
 {
   return   new  Product 
  {
   ProductId  =   0 ,
   CategoryId  =  parentCategory,
   Position  =  position
  };

 }
}
    
        首先要说明的是 OnNameChanging方法,该方法的声明如下(位于Shop.dbml中):     
     
partial   void  OnNameChanging( string  value);
    
        并且在dbml中相应的产品"Name"属性中对其进行调用:
  
[Column(Storage = " _Name " , DbType = " NVarChar(250) NOT NULL " , CanBeNull = false )]
     public   string  Name
    {
             get
            {
                 return   this ._Name;
            }
             set
            {
                     if  (( this ._Name  !=  value))
                    {
                         this .OnNameChanging(value);
                         this .SendPropertyChanging();
                         this ._Name  =  value;
                         this .SendPropertyChanged( " Name " );
                         this .OnNameChanged();
                    }
            }
    }

         这样做的目的就是在产品的名称发生变更时调用该方法以进行处理,当然该set中还有一些其它方法的调用,这里要不多做说明了。下面接着看一下partial类中OnNameChanging方法所做的工作:
 
     partial   void  OnNameChanging( string  value)
    {
        value.Label( " Name " ).IsRequired();
    }

    
        看到这里,如果大家之前看过我写的    
         注:Suteki.Shop的作者在 这篇文章中提到过,这种架构方式是吸取了 Ayende  这篇文章的思想。而 Ayende就是 Rhino.Commons,Rhino Mocks等软件作者。
        下面是其相关的接口声明:    
   
  public   interface  IRepository < T >   where  T :  class
    {
        T GetById( int  id);
        IQueryable < T >  GetAll();
         void  InsertOnSubmit(T entity);
         void  DeleteOnSubmit(T entity);
        [Obsolete( " Units of Work should be managed externally to the Repository. " )]
         void  SubmitChanges();
    }

     public   interface  IRepository
    {
         object  GetById( int  id);
        IQueryable GetAll();
         void  InsertOnSubmit( object  entity);
         void  DeleteOnSubmit( object  entity);
        [Obsolete( " Units of Work should be managed externally to the Repository. " )]
         void  SubmitChanges();
    }

     
         做为实现上面两个接口的“Repository”类,其承担了对CRUD的具体操作逻辑实现。   
   
  public   class  Repository < T >  : IRepository < T > , IRepository  where  T :  class
    {
         readonly  DataContext dataContext;

         public  Repository(IDataContextProvider dataContextProvider)
        {
            dataContext  =  dataContextProvider.DataContext;
        }

         public   virtual  T GetById( int  id)
        {
            var itemParameter  =  Expression.Parameter( typeof (T),  " item " );

            var whereExpression  =  Expression.Lambda < Func < T,  bool >>
                (
                Expression.Equal(
                    Expression.Property(
                        itemParameter,
                         typeof (T).GetPrimaryKey().Name
                        ),
                    Expression.Constant(id)
                    ),
                 new [] { itemParameter }
                );

             return  GetAll().Where(whereExpression).Single();
        }

         public   virtual  IQueryable < T >  GetAll()
        {
             return  dataContext.GetTable < T > ();
        }

         public   virtual   void  InsertOnSubmit(T entity)
        {
            GetTable().InsertOnSubmit(entity);
        }

         public   virtual   void  DeleteOnSubmit(T entity)
        {
            GetTable().DeleteOnSubmit(entity);
        }

         public   virtual   void  SubmitChanges()
        {
            dataContext.SubmitChanges();
        }

         public   virtual  ITable GetTable()
        {
             return  dataContext.GetTable < T > ();
        }

        IQueryable IRepository.GetAll()
        {
             return  GetAll();
        }

         void  IRepository.InsertOnSubmit( object  entity)
        {
            InsertOnSubmit((T)entity);
        }

         void  IRepository.DeleteOnSubmit( object  entity)
        {
            DeleteOnSubmit((T)entity);
        }

         object  IRepository.GetById( int  id)
        {
             return  GetById(id);
        }
    }

    
         在上面的类图中,还有两个类也很重要,其中IRepositoryResolver是一个分析器接口,其定义了“传入一个type类型并在Castle容器中获取该type组件实例的方法声明”,而作为其接口具体实现,“RepositoryResolver”的实现代码如下:
   
 
  public   class  RepositoryResolver : IRepositoryResolver
    {
         private   readonly  IKernel kernel;

         public  RepositoryResolver(IKernel kernel)
        {
             this .kernel  =  kernel;
        }

         public  IRepository < T >  GetRepository < T > ()  where  T :  class  
        {
            Type repositoryType  =   typeof (IRepository <> ).MakeGenericType( new [] {  typeof (T) });

            var repository  =  kernel.Resolve(repositoryType)  as  IRepository < T > ;
             if  (repository  ==   null )
            {
                 throw   new  ApplicationException(StringExtensions.With( " Could not find IRepository<{0}> in kernel "typeof (T).Name));
            }
             return  repository;
        }

         public  IRepository GetRepository(Type type)
        {
            Type repositoryType  =   typeof (IRepository <> ).MakeGenericType( new [] { type });

            var repository  =  kernel.Resolve(repositoryType);
            
             if  (repository  ==   null )
            {
                 throw   new  ApplicationException( " Could not find IRepository<{0}> in kernel " .With(type.Name));
            }

             if  ((repository  as  IRepository)  ==   null )
            {
                 throw   new  ApplicationException( " The repository that implements IRepository<{0}> does not implement IRepository " .With(type.Name));
            }

             return  (IRepository)repository;
        }
    }
   
           上面的部分代码涉及到了castle框架的核心功能,可以参见我写的          
}
 



本文转自 daizhenjun 51CTO博客,原文链接:http://blog.51cto.com/daizhj/161776,如需转载请自行联系原作者
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值