Categories

Links

理解ado command的parameters集合

如果不仔细了解command的parameters集合的举止的话,你会感到很迷惑的。
parameters有个refresh方法,它会查询数据源以了解你的存储过程或sql语句的参数信息
如:select * from customerinfo where id=? and name=?

调用refresh方法会产生两个参数,名字是param? ,?从1开始


refresh会自动调用,这个自动调用的前提是你 用以下的方法会调用访问parameters集合
vj
cmd.getParameters().getCount();
或者是
cmd.getParameters().getItem(0)
在vb中
cmd.Parameters.count
for each p in cmd.Parameters
next

相反,避免使用上述方法,直接使用append则不会自动调用refresh,这节省了一次数据库往返,在你斤斤计较性能你可能需要这样做。

调用或自动调用refresh的好处是可见的,它会自动设置参数的数据类型和大小,方向等属性,而使用append,你需要自行进行设置。坏处是需要一次数据库往访,而且不是所有的数据库均支持该功能

 

[2005-02-18 13:48:53 | Author:jiangjianxiao ] [] 4 comments

属性是仅仅是语法糖衣吗?

或许我以前是这样认为,但现在不是了。因为属性已经同.net 的很多语境联系起来了,如数据绑定,像ormapping中的映射等。

大家可能已经知道,C#把属性保存为set_,get_的方法对,我不知道这是不是clr的规范,但这显然已经影响到j#

看看j#中
假如我有个Category类,有个name属性,在j#中,你必须声明
/**
  * @property
  */
 public void set_Name(String name)
 {
 }
 /**
  * @property
  */
 public String get_Name()
 {
  //
 }

 

大家知道,如果要符合缺省的javabeans规范(javabeans允许你实现BeanInfo接口来改变这种行为,但因为这个_而这样做,根本没有必要)规范,则应该写成
public void setName(Sring name);

public String getName();

简单的一个_,就破坏了实体类的迁移特性,这真是一件非常糟糕的事情,虽然hibernate允许你使用field使用进行映射,但其它.net程序根本不会兼顾这点

同样的情况,出现在j#使用.net 类库的情况中,所有的属性均是用set_,get_来访问,个人以为这是个败笔,因为这违背java程序员习惯。在vj++中,使用或创建com时,是没有_的

进一步联想,ms向来是以数据为中心,相对于java动不动以对象为中心而言。本来用ado或是ado.net也没有什么问题,但当编程环境特别对之提供支持时,得确影响到很多人的决定。比方说
vb6 ,vj6在数据绑定上支持recordset,现在的.net环境对dataset,datareader的绑定上的支持也特别好,虽然.net 2.0在对象的绑定上有了一定的进步,如objectdatasource.但这种特点对很多应用决策的影响是非常明显的。带来的直接后果是,这程序是难以迁移的,这个迁移不仅仅是指从.net和java之间,就连com到.net也是如此。

我了解很多公司都有两条腿走路的想法,对java或.net同时提供支持。我个人对此也非常有兴趣,有时我在想,迁移代码事实上可能并不现实,有太多的陷井在里面。继续深入吧,或许会改变我的一些看法......

[2005-02-06 10:45:04 | Author:jiangjianxiao ] [] 1 comments

component,site,container(初稿)

最早在wfc中引入的component,site,container延伸到.net 。 [h3]wfc阶段[/h3] 在com.ms.wfc.core中,定义了三个接口: IComponent,IComponentSite,IContainer 三个缺省实现:Component,Container.Site,Container Container内部持有IComponentSite的数组 当一个Component加入到container,实际上是先构建了一个包含Component的Site对象,再加入到IComponentSite数组的 当将component加入到Container,Container会调用IComponent接口的setComponentSite方法,传入一个IComponentSite实例。这时,你可以在setComponentSite方法中,通过IComponentSite的getContainer方法获得Container对象,然后调用Container的getComponent方法[b]按名[/b]获得其它组件来解决依赖问题。 也可以调用IComponentSite的getService(class)方法按类型来获取其它组件(Component的getService(class)方法,只是简单的调用IComponentSite上的getService(class)。不过在wfc这实际上不可行,在下面会讲到。 这就是 Lightweight Containers and Plugin Architectures: Dependency Injection and Dynamic Service Locators in .NET 的出发点。具体的可参见下面两个链接。 http://weblogs.asp.net/cazzu/archive/2004/05/10/129140.aspx http://www.urbanpotato.net/default.aspx/document/1757 这种设计其一解决了组件的生命周期问题,即当容器dispose时,将依次调用组件的dispose方法 其二是引入了Site这个中间层 [quote] 站点将 Component 绑定到 Container 并启用它们之间的通讯,同时为该容器提供了一种管理其组件的方法。 站点也可以用作容器特定信息、基于组件信息(如组件名)的储存库。 [/quote] 下面的虚构的j++代码 [code] import com.ms.wfc.core.Component; public class EmployeeDao extends Component { public Employee findById(int id){ return new Employee(); } } [/code] [code] import com.ms.wfc.core.Component; import com.ms.wfc.core.IComponentSite; public class EmployeeService extends Component { private EmployeeDao employeeDao; public void setComponentSite(IComponentSite site) { //当容器dispose时,将调用setComponentSite(null) if (site!=null) employeeDao=(EmployeeDao)site.getContainer().getComponent("employeeDao"); } public Employee findById(int id){ return employeeDao.findById(id); } } [/code] 使用 [code] Container serviceContainer=new Container(); serviceContainer.add(new EmployeeDao(),"employeeDao"); serviceContainer.add(new EmployeeService(),"employeeService"); EmployeeService service=(EmployeeService)serviceContainer.getComponent("employeeService"); Employee emp=service.findById(1); assertNotNull(emp); [/code] 当然,ioc一般都是以类型(Type/class)来定位一个具体的实现,如 picocontainer [code] MutablePicoContainer pico = new DefaultPicoContainer(); pico.registerComponentImplementation(Apple.class); pico.registerComponentImplementation(Juicer.class); pico.registerComponentImplementation(Peeler.class); Juicer juicer = (Juicer) pico.getComponentInstance(Juicer.class); [/code] 反编译Container$Site.class,你会发现 public Object getService(Class class1) { return null; } 同样,你也没有在Container中发现void add(class)这样的方法,通过一个class来定位一个服务对象对象在wfc中实际上并没有做 在wfc,这方面还是很粗糙的,像getComponent(String)实现也是简单的遍历数组,没有考虑效率问题 [h3].net的扩展[/h3] IComponentSite改名为ISite IComponent的接口基本相同,仅仅暴露一个 ISite属性 public abstract void removeOnDispose(EventHandler eventhandler); public abstract boolean getChildOf(IComponent icomponent); public abstract void addOnDispose(EventHandler eventhandler); 被移去 IContainer没有什么变化,但新的IServiceContainer,提供了AddService和RemoveService方法 注意: [C#] void AddService( Type serviceType, ServiceCreatorCallback callback ); 这个方法相当于spring的lazy init,即在需要时才请求加载服务 IServiceProvider接口也被引入 在ServiceContainer的简单实现中,IServiceProvider接口的实现可作为构造参数传给ServiceContainer,使ServiceContainer能从之获得另一个实现IServiceContainer接口的实例作为父容器 整个结构还是类似,Component实现IComponent接口,Container实现IContainer,而Container.Site内部类实现ISite接口 IContainer接口和IServiceContainer之间并没有继承关系,在.net中,Container没有getComponent,因此,通过继承Container,并代理一个ServiceContainer是一种方法。这就是在上面第二个链接中AppContainer的实现思路 由于容器持有组件的引用,当组件没有被释放,容器不会被释放,在上面的第二个链接中,展现了一种不好的编程习惯.这里预先加以说明。我自己想了半个小时才明白:( [STAThread] static void Main() { AppContainer c = new AppContainer(); Form1 f = new Form1(); c.Add(f); Application.Run(f); } 这里,c 应该声明为类级,这样才能表达其真正的生存期 static AppContainer c = new AppContainer(); [STAThread] static void Main() { Form1 f = new Form1(); c.Add(f); Application.Run(f); } 下面的代码也应该被修改 private void Form1_Load(object sender, System.EventArgs e) { IServiceContainer s = GetService(typeof(IServiceContainer)) as IServiceContainer; s.AddService(typeof(StatusBar), statusBar1); } 注意,在这里Form1是一个Component,Component的GetService总是被转发给site实例(在wfc是Container.Site,.net 也是)。在.net中实现IContainer接口的类在GetService在需要获取IContainer实现时,总是返回其自身,这行代码,其实就是获取AppContainer Component.GetService [code] protected virtual object GetService(Type service) { ISite site1 = this.site; if (site1 != null) { return site1.GetService(service); } return null; } [/code] Contaniner.Site.GetService [code] public object GetService(Type service) { if (service != typeof(ISite)) { return this.container.GetService(service); } return this; } [/code] Container.GetService [b]Container的GetService只能返回IContainer的实现,而且只返回容器自身,ServiceContainer在请求IServiceContainer实例时返回其自身[/b] [code] protected virtual object GetService(Type service) { if (service != typeof(IContainer)) { return null; } return this; } [/code] 因此, [code] IServiceContainer s = GetService(typeof(IServiceContainer)) as IServiceContainer; [/code] 这行实际上就是返回了c.Services [code] private void Form1_Load(object sender, System.EventArgs e) { c.Services.AddService(typeof(StatusBar), statusBar1); } [/code] 其他类推 [h3]结论[/h3] component,site,container只能算是servicelocator(服务定位),而不是ioc,它还没有解决依赖,你需要手动定位组件以解决以来。当然在其基础可实现自己的容器解决这个问题 实现IComponent,在wfc中,显然比较麻烦(方法太多),在.net 中,这问题得到了缓解。而继承Component,显然不是个好策略。
[2005-02-02 11:52:09 | Author:jiangjianxiao ] [] 1 comments

J++ was a beautiful thing

今天看 theserverside 上的一个贴时看到的

http://www.theserverside.com/news/thread.tss?thread_id=25242

引用:

Ted: "J++ was a beautiful thing: the power of COM with the simplicity of the Java language and platform. It's no accident that some of the features of the .NET platform stemmed from Microsoft's work here"

Agree. With Java (J++) COM was easy in fact it was the best way to make COM objects in the MS world. Also it worked very well with old fashion ASP you could call Java COM objects directly from your ASP code. To work with a script language but being able to use Java for anything more serious was very was very productive. A nice "this is how it should be" feeling.

And to think how people hollowered and yellered in satisfaction when all this was destroyed and teared down!

It is almost as if you loose faith in the human race :).

看来同我持一样观点的人还是不少的

[2005-02-01 13:03:52 | Author:jiangjianxiao ] [] 16 comments

spring.net 的话题

spring.net 开发团队正在加紧进行0.6版本的发布

从cvs来看,0.6正在进一步顺应.net的习惯,像配置文件中,class attribute修改成type,map element为dictionary。移去了IDisposableObject 接口,替换为.net 内置的IDisposable接口。

除了随spring.web引入的 object navigation外,Spring.Pool,Spring.Threading也被加入到spring.net中
随着castle 的推出,spring.net现在有了一个竞争对手了,这是件好事。当前,spring.net除了核心,在实际的开发中缺少帮助,如
spring.data
显然,从IAdoOperations接口和SqlClientTemplate来看,spring.data已经不同spring java的版本。在java实现中,基于接口的匿名类回调是其主要特点。而在spring.net 中,IAdoOperations仅仅是映射microsoft application data block
当然,这是因为C#没有匿名类,只有C# 2.0有匿名方法,这是迁移的最大障碍。但显然,spring.net 不会扔下.net 1.1.
在邮件列表中,关于是否顺应java版本的设计有个讨论
开发者(Griffin)发表了他的观点,主要如下:

Definitely.  I think that the data access code ( ADO.NET ) is radically
different than JDBC. (ado.net从根本上不同于jdbc)
It's typical in the .NET world to use DataSets AS business objects.(在.net中,典型的用dataset表现商业对象)

作者显然很喜欢强类型的dataset,这意味着,可能无法在spring.net中看到java方式的数据访问代码.我个人喜欢java版本的设计.但我也认为,明确ado.net和jdbc的差异是有益的.
用强类型dataset完成entity层设计,无需学习nhibernate之类的ormapping工具.是一种quick and dirty的解决方案.可以预见的事,我会在今后的小项目中采用这种方案.

spring.web
显然,spring.web当前没有提出一个mvc的框架,是在准备中,还是根本没有?

spring.service
cvs上当前是的对Remoting 的支持,对windows service的支持可在http://it.geocities.com/fspinazzi/Spring.Service.2.zip 下载 这部分没什么可说的

因此,有人建议更多的引入其他的解决方案,如
如引入.net mvc2的框架 NWAF:
http://www.codeproject.com/aspnet/NWAF.asp
http://weblogs.asp.net/ngur/archive/2004/11/30/272489.aspx

spring.web 的作者Aleksandar Seovic随后在邮件列表中介绍了其开发思路
1. "Code behind" classes will be used as controllers.
2. Event handlers, either within the code behind class or in
external class will represent actions.
3. Views will be defined in .aspx files
4. Any object can represent a model
并对nwaf做了一些评论

显然,这说明了我们的一个疑问,在spring.web中不会有mvc 了,从这些观点来看,Aleksandar Seovic的开发观点是相当实际的,从我实际的开发来看。这样做没有什么问题。
从作者的观点来看,作者推荐使用event handler,推荐使用event handler,来表达活动或转向

2005-1-28日  cvs检入了result的支持代码

通过在基类Page中增加一个Results dictionary来完成,在需要转向时调用SetResult(resultname)
允许使用字符串或Result类的实例来表达一个Result,Result类有一个TargetPage属性,表示需要转向的页面,Mode表示转向的方式(Redirect或Transfer),Parameters表示参数,如
<object name="list" type="Spring.Web.Support.Result,Spring.Web">
 <property name="TargetPage"><value>employeelist.spring</value></property>
 <property name="Mode"><value>Redirect</value></property>
</object>

<object name="addEmployee" type="~/form/addemployee.aspx">
 <property name="Results">
  <dictionary>
   <entry key="list"><ref object="list"/></entry>
   <entry key="list2"><value>transfer:employeelist.spring</value></entry>   
  </dictionary>
 </property>
</objects>

字符串可以用transfer:或redirect:开头,?后的将解析为参数


用事件进行result处理(只是我的想法,并没有实用价值,暂时保留在这里吧)

一个page
<object name="addEmployee" type="~/form/AddEmployee.aspx">
</object>

需要一个service类
<object name="employeeService" type="Spring.Sample.EmployeeService,Spring.Sample"/>

进行依赖注入
<object name="addEmployee" type="~/form/addEmployee.aspx">
 <proprty name="EmployeeService"><ref object="employeeService"/></property>
</object>

声明一个事件
声明一个AddEmployeeComplete事件,当新增动作完成时触发
//code behind 类表现为controller
public class AddEmployee : Spring.Web.UI.Page
{

 //事件表达活动
 private event EventHandler AddEmployeeComplete;
 //绑定model
 [Binding("Text",Employee.Name()]
 protected TextBox txtName;
 protected Button cmdAdd;
 //通过ioc实现依赖注入
 public IEmployeeService EmployeeService;
 //任何对象表达为model
 private Employee employee;
 public Employee Employee{
  get{
  if (employee==null)
   employee=new Employee();
  return employee;
  }
 }
 private void cmdAdd_Click(object sender ,EventArgs e)
 {
  EmployeeService.AddEmployee(employee);
  if (ADdEmployeeComplete!=null)
   AddEmployeeComplete(employee,EventArgs.Empty);
 }

}

一个事件订阅类
public class ApplicationDispatcher
{
 public void OnAddEmployeeComplete(object sender,EventArgs e)
 {
  HttpContext.Current.Response.Redirect("~/list.spring");
 }
}
全部声明
<object name="addEmployee" type="~/form/addEmployee.aspx">
 <proprty name="EmployeeService"><ref object="employeeService"/></property>
</object>
<object name="dispatcher" type="Spring.Sample.ApplicationDispatcher,Spring.Sample">
 <listener event="AddEmployeeComplete" method="OnAddEmployeeComplete">
  <ref object="addEmployee"/>
 </listener>
</object>

 

跟踪spring.net 的开发过程非常有益,从简单的认为java的设计优良,到更多的去体现.net的特质.我想,我们得确需要多一点思考,而不是一味的盲从.

 

 

[2005-01-26 12:26:42 | Author:jiangjianxiao ] [] 1 comments

Total 91 Display 66 of 70
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Powered by Google App Engine