夢*追蹤

2013年08月23日

OpenAccess常见问题

Filed under: OpenAccess — light8soft @ 11:13

导读:本文以我自己个人的实际使用方式和经历,列举一些常遇到的问题的解决方案。我在这里继续以Oracle为实例数据库。

创建数据库和表

 SQL Code 
1
2
3
4
5
6
7
CREATE TABLE "Person"
(
    
"PersonId" NUMBER (100NOT NULL,
    
"PersonName" VARCHAR2 (36NOT NULL,
    
"Type" NUMBER (10NOT NULL,
    
PRIMARY KEY ("PersonId")
);

创建项目

  数据库创建后,根据OpenAccess基本操作介绍的方法创建项目,然后打开EntitiesModel.rlinq

常见问题汇总

字段的默认值

  在程序中指定属性默认值的最简单方式是在构造函数中给对应的属性赋相应的值。

 C# Code 
1
2
3
4
5
6
7
8
9
10
namespace Sunny.Model
{
    partial 
class Person
    {
        
public Person()
        {
            
this.PersonName = "Sunny";
        }
    }
}
自增主键

  在Oracle里,一般是通过触发器,使流水号插入主键值。具体操作步骤是:首先,在数据库中创建触序列(Sequence)和触发器。

 SQL Code 
1
2
3
4
5
6
7
8
/*创建序列*/
CREATE SEQUENCE "PersonId" MINVALUE 1 MAXVALUE 999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE;
/*创建触发器*/
CREATE
OR REPLACE TRIGGER "Trigger_Person_Insert" BEFORE INSERT ON "Person" REFERENCING OLD AS "OLD" NEW AS "NEW" FOR EACH ROW
BEGIN
    
SELECT "PersonId".nextval INTO : NEW ."PersonId" FROM dual ;
END;

  然后在Person的属性窗口中,把Identity Mechanism属性设置成DatabaseServerCalculated。

  这样一来,当对象插入到数据库后,就可以通过Person.PersonId属性获取对象的主键值。如果你不需要在这个时候获取这个主键值,也可以不设置Identity Mechanism属性。

  如果你希望在对象插入到数据库之前获取主键值,那么只能在对象插入到数据库前,通过调用序列(Sequence)获取。

  OpenAccess没有对Sequence进行映射封装的机制,只能之前通过Sql获取。

 C# Code 
1
2
3
Sunny.Model.EntitiesModel model = new Sunny.Model.EntitiesModel();
Sunny.Model.Person person = 
new Model.Person();
person.PersonId = model.ExecuteScalar<
int>("SELECT \"PersonId\".nextval FROM dual");
枚举映射

  在Oracle中,字段类型Number是映射到C#中的decimal类型的,但也可以映射到枚举类型。以下介绍操作步骤:

  首先,定义一个枚举。

 C# Code 
1
2
3
4
5
6
7
8
namespace Sunny.Model
{
    
public enum PersonType
    {
        Worker,
        Farmer
    }
}

  然后设置Person中Type的类型为刚刚定义的属性PersonType。

  最后我们可以通过枚举类型查询数据库。

 C# Code 
1
2
3
4
Sunny.Model.EntitiesModel model = new Sunny.Model.EntitiesModel();
foreach (Sunny.Model.Person farmer in model.People.Where(p => p.Type == Sunny.Model.PersonType.Farmer))
{
}
Oracle.DataAccess.dll版本问题

  OpenAccess默认是使用Oracle 10g的Oracle.DataAccess.dll操作数据库的,但实际上也可以使用更高版本(例如是11g)的Oracle.DataAccess.dll来操作数据库。

  具体操作步骤是在项目中引用11g的Oracle.DataAccess.dll后,在web.config或app.config中增加system.data节点指定Oracle.DataAccess.dll的版本。

 XML Code 
1
2
3
4
5
6
7
<configuration>
  
<system.data>
    
<DbProviderFactories>
      
<add name="Oracle Data Provider for .NET" invariant="Oracle.DataAccess.Client" description="Oracle Data Provider for .NET" type="Oracle.DataAccess.Client.OracleClientFactory,Oracle.DataAccess,Version=2.112.3.0,Culture=neutral,PublicKeyToken=89b483f429c47342"/>
    
</DbProviderFactories>
  
</system.data>
</configuration>

2013年08月20日

OpenAccess类之间的关联

Filed under: OpenAccess — light8soft @ 17:41

导读:本文以实际操作为例,介绍在OpenAccess的编辑器中,如何建立两个类之间的关联。我在这里继续以Oracle为实例数据库。

创建数据库和表

 SQL Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
CREATE TABLE "Person"
(
    
"PersonId" RAW (16),
    
"PersonName" VARCHAR2 (36NOT NULL,
    
PRIMARY KEY ("PersonId")
);
CREATE TABLE "Child"
(
    
"ChildId" RAW (16),
    
"PersonId" RAW (16NOT NULL,
    
"ChildName" VARCHAR2 (20NOT NULL,
    
PRIMARY KEY ("ChildId")
);
CREATE TABLE "Worker"
(
    
"PersonId" RAW (16),
    
"Department" VARCHAR2 (20NOT NULL,
    
PRIMARY KEY ("PersonId")
);

创建项目

  数据库创建后,根据OpenAccess基本操作介绍的方法创建项目,然后打开EntitiesModel.rlinq

1对多关系

  在工具箱中选择Association,从Child连线到Person,编辑器会弹出对话框。

 

  选择Child.PersonId关联到Person.PersonId,然后点击OK关闭对话框。

 

  这样,Child和Person之间的1对多关联就建立了。可以看见编辑器为Person类添加了一个Children属性,为Child类添加了一个Person属性。

 

  最后,可以在程序中使用这两个属性,访问被关联的对象。

 C# Code 
1
2
3
4
Sunny.Model.EntitiesModel model = new Model.EntitiesModel();
foreach(Sunny.Model.Person person in model.People)
    
foreach (Sunny.Model.Child child in person.Children)
        System.Console.Write(
"Parent Name:{0} Child Name:{1}"child.Person.PersonName, child.ChildName);

1对1关系

  在工具箱中选择Association,从Child连线到Person,编辑器会弹出对话框。

 

  选择Worker.PersonId关联到Person.PersonId,然后点击OK关闭对话框。

 

  这样,Worker和Person之间的1对1关联就建立了。可以看见编辑器为Person类添加了一个Worker属性,为Worker类添加了一个Person属性。

 

  最后,可以在程序中使用这两个属性,访问被关联的对象。

 C# Code 
1
2
3
4
5
Sunny.Model.EntitiesModel model = new Model.EntitiesModel();
foreach (Sunny.Model.Person person in model.People)
    System.Console.Write(
"Person:{0} Department:{1}", person.PersonName, person.Worker == null ? "" : person.Worker.Department);
foreach (Sunny.Model.Worker worker in model.Workers)
    System.Console.Write(
"Person:{0} Department:{1}", worker.Person.PersonName, worker.Department);

  在OpenAccess里,强制规定主键和主键之间的关联是1对1,其他字段和主键的关联是1对多,并且目标类(Taget Class)中的关联字段必须是主键。这种强制不能更改的硬性规则,我自己感觉上不知道会不会有失灵活性。

  除了1对n关联外,OpenAccess还有一种通过中间表关联两个类的多对多关联方式,可以在上面提及的“关联编辑器(Association Editor)”窗口中的“关系视图(Relational View)”选项卡中作这种多对多关联的设置。这里为了保持本文的简洁性不作详述,有兴趣可以自己尝试体会。

继承

  对于Perosn和Worker来说,通过继承来关联,似乎是比1对1关联更加合理的选择。下面演示操作步骤:

 

  首先,删除Worker的PersonId属性,在工具箱中选择Inheritance,从Child连线到Person。

 

  接着在“映射明细编辑器(Mapping Details Editor)”中,选择“继承策略(Inheritance Strategy)”为“纵向(Vertical)”

  除了Vertical,OpenAccess还有Flat和Horizontal两种继承方式。Flat表示派生类和基类都存储在同一张表,Horizontal表示最顶层的基类没有映射到数据库中的任何表。由于这两种继承方式比较少用到,本文不作详述,有兴趣可以的话可以自己尝试一下。

 

  如果Worker没有映射到表,重新选择映射到Worker。

  不知道是不是OpenAccess的Bug,每次建立继承关联的时候,派生类的映射表都会被清空。

 

  最后在属性窗口中,把Worker的Concurrency Mode属性设为Default。

  不这样设的话操作数据库的时候会出错,至于为什么会这样这里就不作详述了,有兴趣可以自己探索一下。

 

  这样,两个类之间的继承关联就设置完毕了。如果在程序中使Worker对象往数据库中添加数据,OpenAccess会同时在Person和Worker两张表中添加数据。

 C# Code 
1
2
3
4
5
6
7
Sunny.Model.EntitiesModel model = new Model.EntitiesModel();
Sunny.Model.Worker worker = 
new Model.Worker();
worker.PersonId = System.Guid.NewGuid();
worker.PersonName = 
"Sunny";
worker.Department = 
"Development";
model.Add(worker);
model.SaveChanges();

2013年07月10日

OpenAccess基本操作

Filed under: OpenAccess — light8soft @ 17:59

导读:本文以一个实例介绍OpenAccess如何对数据库中的表,做最基本的查询、添加、编辑、删除操作

为什么选择OpenAccess?

  据我所知,.Net平台上的ORM框架主要有Entity Framework、Linq to Sql、OpenAccess、dotConnect、XPO几种,我在其中选择OpenAccess的首要原因在于根据Goolge上的搜索结果,OpenAccess比其他ORM优胜。

  其次,Entity Framework的最新版已经不支持.Net Framework 3.5了,但OpenAccess仍然继续支持。因为我们公司的主流.Net开发工具是VS.Net 2008,这意味着OpenAccess是一个更为合适的选择。

  最后,Entity Framework虽然得到了各大厂商的官方支持,但也有美中不足之处。以Oracle为例,Oracle在Oracle Data Access Component 11中增加了对Entity Framework的支持,但Oracle 11的客户端是不能连接9的数据库的。我们公司现时主要使用的数据库是Oracle 9i,这意味着OpenAccess是一个更为合适的选择。

  另外,OpenAccess的开发商是Telerik,我们可以从这家公司的产品线上看到它的实力。

  我想OpenAccess相对来说最大缺点莫过于没有中文版,纠结于英文的人可能比较适用使用Entity Framework。

创建本实例的先决条件

  首先,从官方的下载网页,点击“Automatic Installation”下载OpenAccess。

  http://www.telerik.com/account/your-products/product-versions.aspx?pid=639

  这个页面是需要注册才能进入的,如果懒得注册,可以使用我的账号:livemylive@msn.com:000000

  其次,OpenAccess是通过调用Oracle.DataAccess.dll操作数据库的,所以需要下载并安装Oracle Data Access Component 10

  http://download.oracle.com/otn/other/ole-oo4o/ODAC1020221.exe 

  OpenAccess支持的数据库有很多,但由于我们公司现在使用的是Oracle数据库,所以本文主要针对的还是Oracle数据库。

本实例创建的步骤

  在数据库中创建一个表

 C# Code 
1
2
3
4
5
6
CREATE TABLE "Person"
(
    
"PersonId" CHAR(36) NOT NULL,
    
"PersonName" VARCHAR2(36) NOT NULL,
    primary key (
"PersonId")
)

  在VS.Net中创建解决方案。

 

  在解决方案中添加“Telerik OpenAccess Class Library”项目。

 

  在上图对应的操作窗口中点击“确定”后,将会弹出以下操作向导。

 

  我这里直接填写连接字符串来连接数据库,也可以通过点击“Add New Connection”按钮来连接。

  “Connection String Name”是程序的config文件中,configuration/connectionStrings节点下,存放连接字符串的add节点的name属性的值。

 XML Code 
1
2
3
4
5
<configuration>
    
<connectionStrings>
        
<add name="Model" connectionString="Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.95)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=TEST)));User ID=TEST;Password=0;Enlist=false" providerName="Oracle.DataAccess.Client"/>
    
</connectionStrings>
</configuration>

 

  选择要生成的对象。

 

  这里是生成的变量的命名规则,默认即可。

 

  点击“Browser…”按钮,创建并选择“Generate”作为存放生成文件的目录。

 

  在上图对应的操作窗口中点击“完成”后,打开EntitiesModel.rlinq,更改PersonId的类型为Guid。

 

  更改Person的Identity Mechanism为Guid,大概意思是添加数据的时候,主键插入一个新的Guid。

  更改Person的Concurrency Mode为None。

  Concurrency Mode是并发冲突的处理方式,处理并发冲突会增加编辑、删除数据时的性能负荷,我觉得绝大多数情况都不需要它。所以我建议把所有对象的Concurrency Mode都设成None,如果想了解更多关于“并发冲突”的概念,可以查阅网上相关资料。

  最后在解决方案中,添加一个“Web Application应用程序”项目,并在项目中添加对Model项目的引用。

可能出现的问题

  不知道是不是我机上只安装了Oracle Data Access Component,但没有安装Oracle客户端的原因,在OpenAccess的设计器中有时间会出现找不到Oracle.DataAccess的错误(程序中没有出现这个错误,仅限于设计器)。

  解决方法是,如果在上述选择对象的界面中出现这个错误,点击“Next”跳过这一个步骤。

 

  然后有点怪异的是,点击一下“Add OpenAccess Service…”这个问题就会消失了。

 

  最后打开EntitiesModel.rlinq重新选择对象。

关于整个实例

  本实例通过本文的附件下载,解决方案是VS.Net 2008格式。由于代码的注释都在源文件当中,这里就不重复叙述了。

  实例中演示了对数据库中的Person表做最简单的查询(包括分页)、添加、编辑、删除操作。

  Web项目中List.aspx是列表页面,包括查询、删除功能。Edit是编辑页面,包括添加和修改功能。

  两个项目中都有一个.config文件,OpenAccess设计器在访问数据库的时候,读取的是Model项目中的config文件中的连接字符串所指向的数据库。但实际上程序运行的时候,OpenAccess读取的时候调用它的那个程序的config文件,即Web项目中的config文件。

  要运行这个本实例,在数据库中建表后,修改config文件中的连接字符车即可。

关于数据类型的映射

  在Sql Server数据库中,字段的每种数据类型在C#里都有明确对应的变量类型。但在Oracle当中,情况又不一样。例如Oracle建议统一使用Number作为数字类型,而不要使用Integer、Int等类型。Oracle的Number默认对应C#的类型是decimal,但更多时候,我们需要的是int。所以很多时候需要在设计器中更改属性的类型。

  有鉴于此,在这里列出.Net和Oracle对应的数据类型作参考。

.NET

Oracle data types

System.Boolean NUMBER(1)
System.Byte NUMBER(3)
System.Byte[] BLOB
System.DateTime TIMESTAMP
System.DateTimeOffset TIMESTAMP WITH TIME ZONE
System.Decimal NUMBER
System.Double NUMBER
System.Guid CHAR(36)/RAW(16)
System.Int16 NUMBER(5)
System.Int32 NUMBER(10)
System.Int64 NUMBER(19)
System.SByte NUMBER(3)
System.Single NUMBER(15,5)
System.String VARCHAR2
System.TimeSpan INTERVAL DAY TO SECOND

  下一篇日志,将讨论在实际中OpenAccess更多细节上的使用技巧。

  本文附件:OpenAccessBasic

  附件实际上是.zip文件,因为博客系统的限制,改成了doc,下载后改回zip扩展名即可打开。

2013年07月3日

Linq基础简介

Filed under: OpenAccess — light8soft @ 10:11

导读:本文旨在以最简单的方式描述Linq的最基本和常用的使用方法,如果你希望对相关知识有更深层次的了解,可以在网上查阅其它相关资料。

什么是Linq?

  细心的人应该已经发现,在VS.Net 2008(或以上本版)新建一个WebForm(*.aspx)或其他类文件后,已经在该.cs文件的using部分已经添加了对Linq命名空间的引用:

 C# Code
1
using System.Linq;

  现在我们在这个.cs文件里的一个方法中,定义一个集合对象,然后通过VS.Net的智能提示浏览它包含的方法:


  标示了“下箭头”的方法就是System.Linq命名空间下定义的扩展方法。如果移除了“using System.Linq;”这一行,也就看不到这些方法了:


 根据我自己的理解,Linq就是定义在System.Linq命名空间下的一组针对集合对象的扩展方法。

  我所说的“集合对象”是指继承了System.Collections.IEnumerable接口的类对象,最常见集合对象的包括Array(string[]和int[]等)和List等,当然还包括这里的主角System.Linq.Queryable。但本文并不讨论Queryable,因为它涉及Linq深一层次的工作原理,不在本文的讨论范围内,如果你对此感兴趣,可以查询网上相关资料。

几个最常用的Linq方法

Where

  与Sql中的where类似,Linq中的Where返回集合中符合条件的记录。

 C# Code 
1
2
3
4
int[] numbers = { 0123456789 };
var smallNumbers = numbers.Where(n => n < 
5);
foreach (int number in smallNumbers)
    System.Console.WriteLine(
"小于5的数字:" + number);

  以上代码筛选出集合里面小于5的元素。

关于以上代码的解释:

  在C#里,var关键字表示隐式声明类型,类型由“=”右面的方法返回的类型决定。跟java script不同,C#里的var关键字声明的变量实际上是有明确的类型的,只是在代码中省略不标明,并且在声明后不能更改他的类型。在可以不使用var的情况下,我建议还是写明变量的类型,以增强代码的可读性。例如上“var smallNumbers = numbers.Where(n => n < 5)”等同于“System.Collections.Generic.IEnumerable<int> smallNumbers = numbers.Where(n => n < 5)”

  “n => n < 5”是一个Lambda表达式,Lambda表达式在C#里面是匿名委托/delegate(初学者可以暂时理解为匿名方法)的简写形式,n是方法的参数,“n <
5”是返回值(“<”返回bool),实际上“n => n < 5”也可以用一个委托代替。如果你想了解更多,可以查阅网上关于C# Lambda表达式的相关资料。

Any

  Any判断集合内是否存在符合条件的元素。

 C# Code 
1
2
3
4
int[] numbers = { 0123456789 };
if (numbers.Any(n => n < 5))
{
}
OrderBy和OrderByDescending

  OrderBy和OrderByDescending这两个方法的功能和Sql中的order by x和order by x desc类似。如果根据多个字段排序,后面再接上ThenBy或ThenByDescending。

 C# Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class FullName
{
    
/// <summary>
    /// 姓
    /// </summary>
    public string FirstName;
 
    
/// <summary>
    /// 名
    /// </summary>
    public string LastName;
 
    
public FullName(string firstName, string lastName)
    {
        
this.FirstName = firstName;
        
this.LastName = lastName;
    }
}
 
public void OrderTest()
{
    FullName[] names = { 
new FullName("张""三"), new FullName("李""四") };
    var orderedNames = names.OrderBy(n => n.FirstName).ThenByDescending(n => n.LastName);
}
Contains

  Contains方法在查询数据库时,功能和Sql中的like语句类似,查询字段是否包含指定的字符串。

 C# Code 
1
2
string[] names = { "Terry""Andy""King" };
var yNames = names.Contains(
"y");

  另外,Contains方法在查询数据库时,也有和Sql中的in语句类似的功能。

 C# Code 
1
2
3
FullName[] fullNames = { new FullName("张""三"), new FullName("李""四") };
string[] firstNames = { "张""黄""何" };
var names = fullNames.Where(n => firstNames.Contains(n.FirstName));
Select

  Select返回该参数内返回的对象集合:

 C# Code 
1
2
FullName[] names = { new FullName("张""三"), new FullName("李""四") };
var orderedNames = names.Select(n => 
new { n.FirstName, n.LastName });

  以上代码在姓名的集合中,取出FirstName和LastName两个属性组成一个新的集合。

关于以上代码的解释:

  “new{}”在C#中的作用是定义一个匿名对象,匿名对象使用前是不需要声明的,所以声明匿名对象的变量,只通过var关键字。如果我们想在匿名对象中使用别名,可以使用“=”操作符,例如“new { n.FirstName, n.LastName }”可以写成“new { FirstName =n.FirstName, LastName =n.LastName }”。针对这段代码,如果我们想把整个FullName对象取出来,可以把“n => new { n.FirstName, n.LastName }”写成“n => n”

Count

  与Sql中的count类似,Linq中的Count返回集合中的元素个数:

 C# Code 
1
2
int[] numbers = { 0123456789 };
int totalCount = numbers.Count();

Count方法也可以带条件参数:

 C# Code 
1
2
int[] numbers = { 0123456789 };
int smallNumberCount = numbers.Count(n => n < 5);

  在Linq中,Count方法常用于分页,告诉分页控件一共有多少条记录。

Skip和Take

  Skip方法的功能是跳过集合里指定数量个数的元素,取往后的元素。

  Take方法的功能是取集合里指定个数的元素。

  这两个方法在Linq里的最主要作用是用作分页:

 C# Code 
1
2
3
4
int[] numbers = { 0123456789 };
int pageSize = 3;
int pageIndxe = 1;
var secondPageNumbers = numbers.Skip(pageSize *pageIndxe).Take(pageSize);
First

  Frist返回集合内符合条件的第一个元素,在数据库操作中,常用于根据主键返回对象:

 C# Code 
1
Parent parent = parents.First(p = > p.ParentId == 1);
FirstOrDefault

  FirstOrDefault的功能和First一样,但First在集合内没有符合条件的元素的时候会抛出异常,而FirstOrDefault在这种情况下返回null。

C#在语法级别上对Linq的支持

  C#专门为Linq制定了一些的关键字来使Linq的表达方式更加优雅:

 C# Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/// <summary>
/// 父母
/// </summary>
public class Parent
{
    
/// <summary>
    /// 编号
    /// </summary>
    public int ParentId;
 
    
/// <summary>
    /// 姓名
    /// </summary>
    public string ParentName;
 
    
public Parent(int id, string name)
    {
        
this.ParentId = id;
        
this.ParentName = name;
    }
}
 
/// <summary>
/// 子女
/// </summary>
public class Child
{
    
/// <summary>
    /// 子女编号
    /// </summary>
    public int ChildId;
 
    
/// <summary>
    /// 父母编号
    /// </summary>
    public int ParentId;
 
    
/// <summary>
    /// 姓名
    /// </summary>
    public string ChildName;
 
    
public Child(int childId, int parentId, string name)
    {
        
this.ChildId = childId;
        
this.ParentId = parentId;
        
this.ChildName = name;
    }
}
 
Parent[] parents = { 
new Parent(1"张三"), new Parent(2"李四") };
Child[] children = { 
new Child(11"小红"), new Child(22"小明") };
 
var people1 = from child 
in children
              join parent 
in parents on child.ParentId equals parent.ParentId
              where child.ParentId > 
0 && child.ParentId < 100
              orderby child.ParentId, child.ChildId
              select 
new
              {
                  child.ChildName, parent.ParentName
              };
//等同于
var people2 = children.Where(c => c.ParentId > 0 && c.ParentId < 100)
              .OrderBy(c => c.ParentId)
              .ThenBy(c => c.ChildId)
              .Join(parents, c => c.ParentId, p => p.ParentId, (c, p) => 
new { c.ChildName, p.ParentName });

  从以上代码可以看出,使用关键字的查询语句比使用函数的表达方式更简洁和优雅,但使用函数式在多行代码拼凑组合时比较灵活。我自己觉得美中不足的是,很多Linq方法都没有制定成关键字,例如Count、Skip和Take等。

其他查询句法

  文本介绍的查询句法,在大多数场合中已经够用。但某些场合,我们会用到另外一些查询句法(我想特别是聚合查询),如果你对此感兴趣,可以查阅网上的相关资料,否则可以在用到的时候再去查:

http://www.cnblogs.com/zoupeiyang/archive/2011/06/25/2090004.html

Linq的缺陷

  我自己觉得Linq的缺陷主要在于Sql中的right outer join和full outer join在Linq里面并没有对应的查询方法,我不知道其他人或者微软有没有把这些看成缺陷,有没有打算在将来添加这两个功能。

2011年02月10日

善欲人見的動機

Filed under: 新闻与政治 — light8soft @ 16:05

  右手行善莫讓左手知曉,新約聖經如是說。

  中國人向來講究施恩不求回報,為善不欲人知。朱子治家格言:善欲人見,不是真善;惡恐人知,便是大惡。

  陳光標傾囊助窮,贏得身前身後名,既收獲了風光美名,也種上了偽善惡名。台灣的星雲法師便看破其中的玄機,派人送金剛經給陳光標,其中之喻,就是勸陳光標不僅要看破利之所誘,更要看透名之所惑,真正做到無欲則剛。星雲法師贈經之舉,一切盡在不言中,求名心切的陳光標是否能頓悟其中真意呢?

  陳光標高調行善,島內不少民眾跪求紅包。為了錢,不少台灣人甚麼事都做得出來,不吃嗟來之食的古訓早已拋之一邊。陳光標所到之處,簡直就像「中標」現象,跪的跪,倒的倒,哭的哭,喊的喊,甚至有些青年男子不顧「男兒膝下有千金」的尊嚴,在街頭攔跪,還有一名婦人居然為流浪犬跪求小車一輛,這些場面看得讓人觸目驚心。

  陳光標今次行善騷,成就了陳光標一人之名,卻讓中華民族付出了巨大代價,更讓外國人看盡笑話。有錢能使鬼推磨,中國人在錢面前永遠站不起來,挺直不了腰桿。

最知名的日本人物

Filed under: 历史、文化 — light8soft @ 15:55

  據了解,目前在中國最知名的日本人物,既不是菅直人,也不是小泉純一郎,而是AV女優蒼井空和鈴木杏里。前者去年在中國一家網站開通微博,短短十四個小時內,便受到十九萬五千五百九十九位中國粉絲追捧。期間她僅僅發布了一條禮節性的微博,卻獲得近四萬五千次轉發和近三萬條評論。

  蒼井小姐曾多次來華演出,均引起巨大轟動,堪稱高潮迭起,很多人尊稱她「蒼老師」。雖然她僅二十七歲芳齡,但在人體動作技術方面確實達到了爐火純青的境界,許多男孩子都是因為欣賞她的表演才變成男人的;成年人同樣感到大開眼界,並嘆息以前都是白活。去年四月,蒼井空在微博上發起為玉樹地震賑災募捐後,被網友冠上「德藝雙馨」的牌匾,稱讚她「不僅有美麗的身體,還有美麗的心靈」。據說她正在灌錄一首中文歌曲《毛衣》,準備獻給最最最愛她的中國人。

  而鈴木杏里亦與中國有深厚的友誼,她上大學時從事歷史專業學習,畢業論文為《日本侵略中國》。她自我表白稱,自己是能夠正視日本侵略中國的人,所以日常生活裏經常免費和中國留學生做愛。「我總覺得這樣子是替過去的侵華做一種心理上的補償,不過坦白說,中國留學生比起日本人來也比較溫柔,可以讓我很舒服!」鈴木杏里親華情結,使其在中國人氣極旺。

2010年05月9日

Firework提示“无法运行脚本,这个命令需要一个活动文档。”的解决办法

Filed under: 计算机与 Internet — light8soft @ 10:19

  首先引发这个问题的原因我自己也不是很清楚,问题的症状是Firework有时候打开一个图片的时候,工具栏所有按钮都会变成不可用,做某些操作(例如保存)的时候会弹出提示“无法运行脚本,这个命令需要一个活动文档。”错误提示框。

  这个问题的解决方法也很简单。首先对打开的图片做一个可引起撤销的操作(例如移动图层),然后关闭图片,最后在弹出的退出确认框里面点击“取消”按钮。这样工具栏变回转会可用,所有操作恢复正常。

2010年01月14日

败毒孙云丰,你让我感到恶心

Filed under: 新闻与政治 — light8soft @ 16:56

  百度首席产品设计师孙云丰写道“Google市侩,我感到恶心”(全文见 http://news.csdn.net/a/20100113/216459.html)

  他这样写道

   “政治环境短期内是无法改变的。在中国,每个企业或者个人,都必须戴着镣铐跳舞。其实在别国一样,只是程度之别。但这是现实。在有限的条件下,尽可能的提供自己勉力而为的一份子,才是一个真切的做企业、做人态度。”

  是的,我也是这么认为,环境恶劣,你可以保持沉默,我甚至认为这是一个经济理性人最明智的选择。

  不过呢。

  并不是每个人都是小人的,没必要把所有的东西都当做阴谋论。

  世界上除了真金白银,除了市场份额,还有一种叫做政治信仰的东西。

  是的,这个世界上真的有人可以为了信仰而去抛头颅,洒热血,只是因为他相信,他所做的代表了正义。

  是的,这个世界上真的有人会去坚持他们为人处世的原则,会去因为在你眼中无足轻重的东西放弃那些荣华富贵,锦绣前程。

  当然,你可以选择没有信仰,你可以认为这是经济利益,你可以以小人之心度君子之腹,这是你的自由。

  但是,对于你的这种说法

   “google的首席法律顾问的调调让我感到恶心。因经济利益退出,就直白白的说好了,把自己涂脂抹粉一番,还煞有介事的提到google被中国人攻击,中国异议分子的Gmail信箱被攻击,把这些事情作为退出中国的铺垫,这种论调是侮辱中国普通老百姓的智商,但还真有可能迎合那帮目空一切,但从未到过中国、对中国没有丝毫了解,却又喜欢对中国说三道四的西方人的假想。”

  我有权抗议。

  请你不要代表我,更不要代表中国普通老百姓。

  你身处大公司,十指不沾阳春水,又怎么知道那些尘埃中挣扎着的小网站在这些日子里被苦苦折腾的悲剧故事。

  鲁迅的两句诗,恰如我此时此刻的心情–“忍看朋辈成新鬼怒向刀丛觅小诗”

  西方人是不了解中国国情,是有些凭空想象,但是,正所谓当局者迷旁观者清,不识庐山真面目只缘身在此山中。

  扭曲过的视角,虽不是事件的真相,但也绝非无中生有,空穴来风。

  兼听则明,偏信则暗。不带逻辑思考,只凭借人种,国籍毫无道理的鄙视,煽动仇恨与敌视,如非别有用心,就是肤浅之极。

   “信息不对称是造成社会不平等最主要的原因之一。而对普通百姓最为关键的信息,并非中-南-海秘闻,而是最为常规的经济、文化、科技等领域信息。尽可能的为普通老百姓对这些领域的信息提供便捷,并消弭信息占有的不对称,这是搜索引擎存在的最大社会政治意义之一。”

  是的,百度是一个好公司,提供了很多有用的信息。

  但是,号称最懂中文,事实上也差不多只懂中文baidu,你可知道,对于一个技术人员来说,Google是多么神圣不可侵犯的领地。

  无论是Google对于英文资料(90%的技术资料都是英文的)的搜索,还是GoogleCode的开源项目Hosting,又或者是高手扎堆云集的Google Groups,第一时间让技术传遍全球的GoogleReader,还有如同空气与水的Gmail。

  太多太多,我一时间甚至数不清。

  Google以它开放的姿态,让程序员真真切切的靠近的知识领域的共产主义。

  请问您,baidu有吗?baidu会有吗?

  当然你可以嗤之以鼻,说这是不过是商业策略,开放的都是非核心。

  可无论这是一小步,还是一大步,这毕竟都是在向着美好,向着光明前进的一步。

  党在三个代表中说到,要代表先进社会生产力的发展要求,要代表先进文化的前进方向。

  我想,Google当之无愧的做到了这些。

  他代表了先进的商业逻辑。

  不知道你是不是学过历史。

   1757年,乾隆二十二年,中国彻底闭关锁国。一道圣旨从京城传到沿海各省,下令除广州一地外,停止厦门、宁波等港口的对外贸易,这就是所谓的“一口通商”政策。这一命令,标志着清政府彻底奉行起闭关锁国的政策。两百多年来,乾隆的这道圣旨一直被视为是导致近代中国落后于世界的祸根。那时的大清帝国,正值鼎盛时期。

  秦人不暇自哀,而后人哀之;后人哀之而不鉴之,亦使后人而复哀后人也。

  你又说到

  “从这个角度而言,尽可能的设法为百姓提供便捷的信息获取技术服务,提供切实的价值,而不是挂羊头卖狗肉的宣称自己dono evil和政府撕破脸皮搞壮烈,才是一种真切的负责态度。找台阶下可以,但不要拿一个高管制国家的民众感情来做台阶,这是极其不道德的。”

  在一个恶劣环境中,有人可以选择苟且偷生–至于是忍辱负重还是为虎作伥那需要时间来证明。

  但是有人宁为玉碎,不为瓦器,宁为鸡口,不为牛后,请您对他们给以应有的尊重。

  这不是找台阶下,这不是挂羊头卖狗肉。

  这是闻一多的拍案而起,横眉怒对国民党的手枪,宁可倒下去,不愿意屈服。

  这是勇敢的海燕,在闪电中间,在怒吼的大海上高傲地飞翔。这是胜利的预言家在叫喊:让暴风雨来的更猛烈些吧。

  总而言之,孙云丰,不管你是出于什么动机写出这样的文章,你都让我感到恶心。

2009年11月8日

卷柏

Filed under: 历史、文化 — light8soft @ 23:19

  卷柏,又名九死还魂草。根能自行从土壤分离,卷缩似拳状,随风移动,遇水而荣,根重新再钻到土壤里寻找水份。因其耐旱力极强,在长期干旱后只要根系在水中浸泡后就又可舒展,故而得名。

  卷柏是多年生直立草本蕨类植物,喜欢安身在乱石山上,生命力极顽强。日本有位生物学家曾发现,用卷柏做成的植物标本,在时隔11年之后,把它浸在水里,它居然“还魂”复活,恢复生机了。

2008年12月14日

周慧敏的聲明全文

Filed under: 转载作文 — light8soft @ 00:23

  我與倪震識於微時,一起共渡過不能盡算的高低起落,早已磨合了一套我們之間的相處藝術。一個人的問題,兩個人去修正;一個人的挫敗,兩個人去承擔。我倆是一個團隊的,沒分高低,輸贏也是一体 。某程度上,周慧敏早已是一位不同面貌的倪震。任誰一方受到傷害,另一方都願抵禦百倍的痛。一起走過將近二十個年頭,絕對不是在一般人的準則下相愛,但外人卻總愛把自己的一套價值觀去評價、批判屬於我倆之間的愛情。

  今天我能夠成為自愛,懂得愛人,擁有著無比勇氣與承擔的女人,請不要小看這個精神伴侶在我背後為我付出過的一切努力,包容,寵愛,照顧與扶持。都生活了這麼久,沒有倪震,成就不了今天的周慧敏。所以我敢大膽向各位說一句:「我的伴侶絕對犯得起這個錯誤」,而這句說話,亦只我一人有資格去定論。看到伴侶事後為我做出的承擔,我馬上就原諒了他,又怎會有某些媒體創作出來的痛哭,拍檯,大罵,這般無稽的謊言呢 ?不到一天,我看到了很多無比荒誕,狠毒,涼薄的炒作與咀咒,妖魔鬼怪都湧進來,愈炒作愈黑暗,致人於死地。

  公眾人物談戀愛要承受異於常人理解的壓力,從當年決定和不按常規行事的倪震談戀愛,就知道是一場革命了,亦沒有失望過。香港這片是非地,無風三尺浪,暗箭來自四方八面,行差踏錯一步就如掉進鬥獸場。當中我們需要的信心,包容,付出是一般情侶無法體會的。顯微鏡下看世界,任誰都難合格。我告訴大家,我們不害怕,也不逃避,只是有點累了。在回復到朋友關係以後,我們要好好享受不用被批判的日子,大家為未來再次裝備出發。我相信身份的改變,疏離不了我們之間微妙的關愛。

  最後,我要向每位真正支持愛護我的朋友說:「我沒枉費與倪震轟轟烈列地愛過,永遠刻骨銘心,此生無憾。而我自己亦都會好好地勇敢活下去,一如過往。」多謝各位。

周慧敏

二零零八年十二月十一日

早前文章 »

The Silver is the New Black Theme 在WordPress.com的博客.

加关注

每发布一篇新博文的同时向您的邮箱发送备份。