NopCommerce学习(2) EntityFramework
NopCommerce-EntityFramework开发:主要是Controller-Service-Repository的开发方式
操作数据库,主要对象是BaseEntity,IDbContext和NopObjectContext,IRepository和EfRepository,NopEntityTypeConfiguration(可以使用EntityFramework提供的EntityTypeConfiguration不使用NopCommerce拓展的NopEntityTypeConfiguration)
以下代码GitBub地址:https://github.com/heshengli/nop
BaseEntity,实体基类
/// <summary>
/// Base class for entities
/// </summary>
public abstract partial class BaseEntity
{
/// <summary>
/// Gets or sets the entity identifier
/// </summary>
public int Id { get; set; }
public override bool Equals(object obj)
{
return Equals(obj as BaseEntity);
}
private static bool IsTransient(BaseEntity obj)
{
return obj != null && Equals(obj.Id, default(int));
}
private Type GetUnproxiedType()
{
return GetType();
}
public virtual bool Equals(BaseEntity other)
{
if (other == null)
return false;
if (ReferenceEquals(this, other))
return true;
if (!IsTransient(this) &&
!IsTransient(other) &&
Equals(Id, other.Id))
{
var otherType = other.GetUnproxiedType();
var thisType = GetUnproxiedType();
return thisType.IsAssignableFrom(otherType) ||
otherType.IsAssignableFrom(thisType);
}
return false;
}
public override int GetHashCode()
{
if (Equals(Id, default(int)))
return base.GetHashCode();
return Id.GetHashCode();
}
public static bool operator ==(BaseEntity x, BaseEntity y)
{
return Equals(x, y);
}
public static bool operator !=(BaseEntity x, BaseEntity y)
{
return !(x == y);
}
}
IDbContext,数据上下文接口
public interface IDbContext
{
/// <summary>
/// Get DbSet
/// </summary>
/// <typeparam name="TEntity">Entity type</typeparam>
/// <returns>DbSet</returns>
IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity;
/// <summary>
/// Save changes
/// </summary>
/// <returns></returns>
int SaveChanges();
/// <summary>
/// Execute stores procedure and load a list of entities at the end
/// </summary>
/// <typeparam name="TEntity">Entity type</typeparam>
/// <param name="commandText">Command text</param>
/// <param name="parameters">Parameters</param>
/// <returns>Entities</returns>
IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters)
where TEntity : BaseEntity, new();
/// <summary>
/// Creates a raw SQL query that will return elements of the given generic type. The type can be any type that has properties that match the names of the columns returned from the query, or can be a simple primitive type. The type does not have to be an entity type. The results of this query are never tracked by the context even if the type of object returned is an entity type.
/// </summary>
/// <typeparam name="TElement">The type of object returned by the query.</typeparam>
/// <param name="sql">The SQL query string.</param>
/// <param name="parameters">The parameters to apply to the SQL query string.</param>
/// <returns>Result</returns>
IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters);
/// <summary>
/// Executes the given DDL/DML command against the database.
/// </summary>
/// <param name="sql">The command string</param>
/// <param name="doNotEnsureTransaction">false - the transaction creation is not ensured; true - the transaction creation is ensured.</param>
/// <param name="timeout">Timeout value, in seconds. A null value indicates that the default value of the underlying provider will be used</param>
/// <param name="parameters">The parameters to apply to the command string.</param>
/// <returns>The result returned by the database after executing the command.</returns>
int ExecuteSqlCommand(string sql, bool doNotEnsureTransaction = false, int? timeout = null, params object[] parameters);
/// <summary>
/// Detach an entity
/// </summary>
/// <param name="entity">Entity</param>
void Detach(object entity);
/// <summary>
/// Gets or sets a value indicating whether proxy creation setting is enabled (used in EF)
/// </summary>
bool ProxyCreationEnabled { get; set; }
/// <summary>
/// Gets or sets a value indicating whether auto detect changes setting is enabled (used in EF)
/// </summary>
bool AutoDetectChangesEnabled { get; set; }
}
IRepository,基础操作接口
/// <summary>
/// Repository
/// </summary>
public partial interface IRepository<T> where T : BaseEntity
{
/// <summary>
/// Get entity by identifier
/// </summary>
/// <param name="id">Identifier</param>
/// <returns>Entity</returns>
T GetById(object id);
/// <summary>
/// Insert entity
/// </summary>
/// <param name="entity">Entity</param>
void Insert(T entity);
/// <summary>
/// Insert entities
/// </summary>
/// <param name="entities">Entities</param>
void Insert(IEnumerable<T> entities);
/// <summary>
/// Update entity
/// </summary>
/// <param name="entity">Entity</param>
void Update(T entity);
/// <summary>
/// Update entities
/// </summary>
/// <param name="entities">Entities</param>
void Update(IEnumerable<T> entities);
/// <summary>
/// Delete entity
/// </summary>
/// <param name="entity">Entity</param>
void Delete(T entity);
/// <summary>
/// Delete entities
/// </summary>
/// <param name="entities">Entities</param>
void Delete(IEnumerable<T> entities);
/// <summary>
/// Delete entity by id
/// </summary>
/// <param name="id"></param>
void Delete(int id);
/// <summary>
/// Gets a table
/// </summary>
IQueryable<T> Table { get; }
/// <summary>
/// Gets a table with "no tracking" enabled (EF feature) Use it only when you load record(s) only for read-only operations
/// </summary>
IQueryable<T> TableNoTracking { get; }
}
NopObjectContext,继承DbContext, IDbContext,具体实现
/// <summary>
/// Object context
/// </summary>
public class NopObjectContext : DbContext, IDbContext
{
#region Ctor
public NopObjectContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
//是否开启懒加载
//((IObjectContextAdapter) this).ObjectContext.ContextOptions.LazyLoadingEnabled = true;
}
#endregion
#region Utilities
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//dynamically load all configuration
//System.Type configType = typeof(LanguageMap); //any of your configuration classes here
//var typesToRegister = Assembly.GetAssembly(configType).GetTypes()
var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => !String.IsNullOrEmpty(type.Namespace))
.Where(type => type.BaseType != null && type.BaseType.IsGenericType &&
type.BaseType.GetGenericTypeDefinition() == typeof(NopEntityTypeConfiguration<>));
//ef自带对象
//var typesToRegister2 = Assembly.GetExecutingAssembly().GetTypes()
//.Where(type => !String.IsNullOrEmpty(type.Namespace))
//.Where(type => type.BaseType != null && type.BaseType.IsGenericType &&
//type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (var type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
//...or do it manually below. For example,
//modelBuilder.Configurations.Add(new LanguageMap());
//移除复数表名的约定
//modelBuilder.Conventions.Remove<PluralizingEntitySetNameConvention>();
//检测数据库是否存在
//Database.SetInitializer<ObjectContext>(null);
base.OnModelCreating(modelBuilder);
}
/// <summary>
/// Attach an entity to the context or return an already attached entity (if it was already attached)
/// </summary>
/// <typeparam name="TEntity">TEntity</typeparam>
/// <param name="entity">Entity</param>
/// <returns>Attached entity</returns>
protected virtual TEntity AttachEntityToContext<TEntity>(TEntity entity) where TEntity : BaseEntity, new()
{
//little hack here until Entity Framework really supports stored procedures
//otherwise, navigation properties of loaded entities are not loaded until an entity is attached to the context
var alreadyAttached = Set<TEntity>().Local.FirstOrDefault(x => x.Id == entity.Id);
if (alreadyAttached == null)
{
//attach new entity
Set<TEntity>().Attach(entity);
return entity;
}
//entity is already loaded
return alreadyAttached;
}
#endregion
#region Methods
/// <summary>
/// Create database script
/// </summary>
/// <returns>SQL to generate database</returns>
public string CreateDatabaseScript()
{
return ((IObjectContextAdapter)this).ObjectContext.CreateDatabaseScript();
}
/// <summary>
/// Get DbSet
/// </summary>
/// <typeparam name="TEntity">Entity type</typeparam>
/// <returns>DbSet</returns>
public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
{
return base.Set<TEntity>();
}
/// <summary>
/// Execute stores procedure and load a list of entities at the end
/// </summary>
/// <typeparam name="TEntity">Entity type</typeparam>
/// <param name="commandText">Command text</param>
/// <param name="parameters">Parameters</param>
/// <returns>Entities</returns>
public IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters) where TEntity : BaseEntity, new()
{
//add parameters to command
if (parameters != null && parameters.Length > 0)
{
for (int i = 0; i <= parameters.Length - 1; i++)
{
var p = parameters[i] as DbParameter;
if (p == null)
throw new Exception("Not support parameter type");
commandText += i == 0 ? " " : ", ";
commandText += "@" + p.ParameterName;
if (p.Direction == ParameterDirection.InputOutput || p.Direction == ParameterDirection.Output)
{
//output parameter
commandText += " output";
}
}
}
var result = this.Database.SqlQuery<TEntity>(commandText, parameters).ToList();
//performance hack applied as described here - http://www.nopcommerce.com/boards/t/25483/fix-very-important-speed-improvement.aspx
bool acd = this.Configuration.AutoDetectChangesEnabled;
try
{
this.Configuration.AutoDetectChangesEnabled = false;
for (int i = 0; i < result.Count; i++)
result[i] = AttachEntityToContext(result[i]);
}
finally
{
this.Configuration.AutoDetectChangesEnabled = acd;
}
return result;
}
/// <summary>
/// Creates a raw SQL query that will return elements of the given generic type. The type can be any type that has properties that match the names of the columns returned from the query, or can be a simple primitive type. The type does not have to be an entity type. The results of this query are never tracked by the context even if the type of object returned is an entity type.
/// </summary>
/// <typeparam name="TElement">The type of object returned by the query.</typeparam>
/// <param name="sql">The SQL query string.</param>
/// <param name="parameters">The parameters to apply to the SQL query string.</param>
/// <returns>Result</returns>
public IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters)
{
return this.Database.SqlQuery<TElement>(sql, parameters);
}
/// <summary>
/// Executes the given DDL/DML command against the database.
/// </summary>
/// <param name="sql">The command string</param>
/// <param name="doNotEnsureTransaction">false - the transaction creation is not ensured; true - the transaction creation is ensured.</param>
/// <param name="timeout">Timeout value, in seconds. A null value indicates that the default value of the underlying provider will be used</param>
/// <param name="parameters">The parameters to apply to the command string.</param>
/// <returns>The result returned by the database after executing the command.</returns>
public int ExecuteSqlCommand(string sql, bool doNotEnsureTransaction = false, int? timeout = null, params object[] parameters)
{
int? previousTimeout = null;
if (timeout.HasValue)
{
//store previous timeout
previousTimeout = ((IObjectContextAdapter)this).ObjectContext.CommandTimeout;
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = timeout;
}
var transactionalBehavior = doNotEnsureTransaction
? TransactionalBehavior.DoNotEnsureTransaction
: TransactionalBehavior.EnsureTransaction;
var result = this.Database.ExecuteSqlCommand(transactionalBehavior, sql, parameters);
if (timeout.HasValue)
{
//Set previous timeout back
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = previousTimeout;
}
//return result
return result;
}
/// <summary>
/// Detach an entity
/// </summary>
/// <param name="entity">Entity</param>
public void Detach(object entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
((IObjectContextAdapter)this).ObjectContext.Detach(entity);
}
#endregion
#region Properties
/// <summary>
/// Gets or sets a value indicating whether proxy creation setting is enabled (used in EF)
/// </summary>
public virtual bool ProxyCreationEnabled
{
get
{
return this.Configuration.ProxyCreationEnabled;
}
set
{
this.Configuration.ProxyCreationEnabled = value;
}
}
/// <summary>
/// Gets or sets a value indicating whether auto detect changes setting is enabled (used in EF)
/// </summary>
public virtual bool AutoDetectChangesEnabled
{
get
{
return this.Configuration.AutoDetectChangesEnabled;
}
set
{
this.Configuration.AutoDetectChangesEnabled = value;
}
}
#endregion
}
EfRepository,IRepository接口的具体实现
/// <summary>
/// Entity Framework repository
/// </summary>
public partial class EfRepository<T> : IRepository<T> where T : BaseEntity
{
#region Fields
private readonly IDbContext _context;
private IDbSet<T> _entities;
#endregion
#region Ctor
/// <summary>
/// Ctor
/// </summary>
/// <param name="context">Object context</param>
public EfRepository(IDbContext context)
{
this._context = context;
}
#endregion
#region Utilities
/// <summary>
/// Get full error
/// </summary>
/// <param name="exc">Exception</param>
/// <returns>Error</returns>
protected string GetFullErrorText(DbEntityValidationException exc)
{
var msg = string.Empty;
foreach (var validationErrors in exc.EntityValidationErrors)
foreach (var error in validationErrors.ValidationErrors)
msg += string.Format("Property: {0} Error: {1}", error.PropertyName, error.ErrorMessage) + Environment.NewLine;
return msg;
}
#endregion
#region Methods
/// <summary>
/// Get entity by identifier
/// </summary>
/// <param name="id">Identifier</param>
/// <returns>Entity</returns>
public virtual T GetById(object id)
{
//see some suggested performance optimization (not tested)
//http://stackoverflow.com/questions/11686225/dbset-find-method-ridiculously-slow-compared-to-singleordefault-on-id/11688189#comment34876113_11688189
return this.Entities.Find(id);
}
/// <summary>
/// Insert entity
/// </summary>
/// <param name="entity">Entity</param>
public virtual void Insert(T entity)
{
try
{
if (entity == null)
throw new ArgumentNullException("entity");
this.Entities.Add(entity);
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
throw new Exception(GetFullErrorText(dbEx), dbEx);
}
}
/// <summary>
/// Insert entities
/// </summary>
/// <param name="entities">Entities</param>
public virtual void Insert(IEnumerable<T> entities)
{
try
{
if (entities == null)
throw new ArgumentNullException("entities");
foreach (var entity in entities)
this.Entities.Add(entity);
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
throw new Exception(GetFullErrorText(dbEx), dbEx);
}
}
/// <summary>
/// Update entity
/// </summary>
/// <param name="entity">Entity</param>
public virtual void Update(T entity)
{
try
{
if (entity == null)
throw new ArgumentNullException("entity");
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
throw new Exception(GetFullErrorText(dbEx), dbEx);
}
}
/// <summary>
/// Update entities
/// </summary>
/// <param name="entities">Entities</param>
public virtual void Update(IEnumerable<T> entities)
{
try
{
if (entities == null)
throw new ArgumentNullException("entities");
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
throw new Exception(GetFullErrorText(dbEx), dbEx);
}
}
/// <summary>
/// Delete entity
/// </summary>
/// <param name="entity">Entity</param>
public virtual void Delete(T entity)
{
try
{
if (entity == null)
throw new ArgumentNullException("entity");
this.Entities.Remove(entity);
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
throw new Exception(GetFullErrorText(dbEx), dbEx);
}
}
/// <summary>
/// Delete entities
/// </summary>
/// <param name="entities">Entities</param>
public virtual void Delete(IEnumerable<T> entities)
{
try
{
if (entities == null)
throw new ArgumentNullException("entities");
foreach (var entity in entities)
this.Entities.Remove(entity);
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
throw new Exception(GetFullErrorText(dbEx), dbEx);
}
}
public void Delete(int id)
{
try
{
T entity = this.Entities.Find(id);
if (entity == null)
throw new ArgumentNullException("entities");
this.Entities.Remove(entity);
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
throw new Exception(GetFullErrorText(dbEx), dbEx);
}
}
#endregion
#region Properties
/// <summary>
/// Gets a table
/// </summary>
public virtual IQueryable<T> Table
{
get
{
return this.Entities;
}
}
/// <summary>
/// Gets a table with "no tracking" enabled (EF feature) Use it only when you load record(s) only for read-only operations
/// </summary>
public virtual IQueryable<T> TableNoTracking
{
get
{
return this.Entities.AsNoTracking();
}
}
/// <summary>
/// Entities
/// </summary>
protected virtual IDbSet<T> Entities
{
get
{
if (_entities == null)
_entities = _context.Set<T>();
return _entities;
}
}
#endregion
}
NopEntityTypeConfiguration,可拓展的抽象类
public abstract class NopEntityTypeConfiguration<T> : EntityTypeConfiguration<T> where T : class
{
protected NopEntityTypeConfiguration()
{
PostInitialize();
}
/// <summary>
/// Developers can override this method in custom partial classes
/// in order to add some custom initialization code to constructors
/// </summary>
protected virtual void PostInitialize()
{
}
}
简单demo:
实体基础代码
public class Student : BaseEntity
{
public string Name { get; set; }
public string CustomProperty { get; set; }
}
/// <summary>
/// 实体映射表nop拓展
/// </summary>
public partial class StudentMap : NopEntityTypeConfiguration<Student>
{
public StudentMap()
{
this.ToTable("Student");
this.HasKey(pa => pa.Id);
this.Property(pa => pa.Name).IsRequired();
}
}
/// <summary>
/// 原生ef,需要调整NopObjectContext的代码
/// </summary>
//public partial class StudentMap2 : EntityTypeConfiguration<Student>
//{
// public StudentMap2()
// {
// this.ToTable("Student");
// this.HasKey(pa => pa.Id);
// this.Property(pa => pa.Name).IsRequired();
// }
//}
public interface IStudentService
{
void Insert(Student stu);
void Update(Student stu);
void Delete(int id);
IEnumerable<Student> GetList();
}
public class StudentService : IStudentService
{
private readonly IRepository<Student> _iStudentRepository;
private readonly IDbContext _iDbContext;
public StudentService()
{
_iDbContext = new NopObjectContext("App");
_iStudentRepository = new EfRepository<Student>(_iDbContext);
}
//Ioc Autofac 调整
//public StudentService(IRepository<Student> iStudentRepositpory,IDbContext iDbContext)
//{
// _iDbContext = iDbContext;
// _iStudentRepository = iStudentRepositpory;
//}
public void Delete(int id)
{
_iStudentRepository.Delete(id);
}
public IEnumerable<Student> GetList()
{
return _iStudentRepository.Table.AsEnumerable();
}
public void Insert(Student stu)
{
_iStudentRepository.Insert(stu);
}
public void Update(Student stu)
{
_iStudentRepository.Update(stu);
}
}
调用代码(使用了简单的consoleApp)
class Program
{
private static readonly IStudentService _iStudentService =
new StudentService();
static void Main(string[] args)
{
Student stu = new Student() {
Name="李四",
CustomProperty="自定义属性2"
};
_iStudentService.Insert(stu);
Console.WriteLine(stu.Name+"");
Console.ReadKey();
}
}
NopCommerce学习(2) EntityFramework的更多相关文章
- NopCommerce学习(1) Caching
redis教程 http://www.runoob.com/redis/redis-tutorial.html 下载地址:https://github.com/MSOpenTech/redis/rel ...
- entityframework学习笔记--001
最近想重新好好学习一下entityframework,于是在院子里找到了一篇不错的博客.下面把学习的过程记录下来,方便以后复习. 学习过程参考大神的博客:http://www.cnblogs.com/ ...
- Web APi之EntityFramework【CRUD】(三)
前言 之前我们系统学习了EntityFramework,个人觉得有些东西不能学了就算完了,必须要学以致用,在Web API上也少不了增(C).删(D).改(U).查(R).鉴于此,我们通过EF来实现W ...
- 基于nopcommerce b2c开源项目的精简版开发框架Nop.Framework
http://www.17ky.net/soft/70612.html?v=1#0-sqq-1-39009-9737f6f9e09dfaf5d3fd14d775bfee85 项目详细介绍 该开源项目是 ...
- 基于nopCommerce的开发框架(附源码)
.NET的开发人员应该都知道这个大名鼎鼎的高质量b2c开源项目-nopCommerce,基于EntityFramework和MVC开发,拥有透明且结构良好的解决方案,同时结合了开源和商业软件的最佳特性 ...
- ABP 初探 之基于EasyUI的CURD
结束了天天加班的项目,项目虽然结束,但还是有点小问题,只能在后期优化当中完成了,本次做项目采用了,MVC.Webapi.Entityframework,在园了里看到了有关ABP的介绍,同样ABP也是最 ...
- entity framework 新手入门篇(3)-entity framework实现orderby,count,groupby,like,in,分页等
前面我们已经学习了entityframework的基本的增删改查,今天,我们将在EF中实现一些更加贴近于实际功能的SQL方法. 承接上面的部分,我们有一个叫做House的数据库,其中包含house表和 ...
- DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(转)
http://www.cnblogs.com/xishuai/p/ddd-repository-iunitofwork-and-idbcontext.html 好久没写 DDD 领域驱动设计相关的文章 ...
- .NET领域最为流行的IOC框架之一Autofac
一.前言 Autofac是.NET领域最为流行的IOC框架之一,微软的Orchad开源程序使用的就是Autofac,Nopcommerce开源程序也是用的Autofac. Orchad和Nopcomm ...
随机推荐
- Python-并发编程(协程)
今天说说协程 一.引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两 ...
- EasyUI combobox 加载JSON数据
Action返回 JSON 格式如下: jsonResult = { total=7,rows=[ {TEXT=技术支持, ID=402894ca4419acf1014419b148a10000}, ...
- Linux下C语言操作MySQL数据库
MySQL是Linux系统下广泛使用的开源免费数据库,是Linux应用程序数据存储的首选. Ubuntu下安装 […]
- CentOS 7运维管理笔记(10)----MySQL源码安装
MySQL可以支持多种平台,如Windows,UNIX,FreeBSD或其他Linux系统.本篇随笔记录在CentOS 7 上使用源码安装MySQL的过程. 1.下载源码 选择使用北理工的镜像文件: ...
- 九、background及相关所有属性
先看看如下所示的视效图应该如何显示背景阴影? #header { height: 180px; background: url(../images./bg.png) no-repeat center ...
- idea maven打不了war包
开发的时候打不了war包,原因是 web.xml有问题或者是在idea里面webroot没有作为web引用, 添加之后WebRoot上面有个地球标志 就ok了
- html tags and attribute集参考
cite 表示引用到某一本书籍名称,默认样式为斜体,q 表示直接引用到里面的话,大块的引用使用block默认样式将增加“双引号” ,关键的词用<b>默认为粗体:一些技术术语则用<i& ...
- 针对通过 SSH 连接到 Azure Linux VM 时发生的失败、错误或被拒绝问题进行故障排除
尝试连接到 Linux 虚拟机 (VM) 时,有多种原因可能会导致安全外壳 (SSH) 错误.SSH 连接失败或被拒绝. 本文帮助用户找出原因并更正问题. 可以使用 Azure 门户.Azure CL ...
- CentOS7 安装tomcat为系统服务器 Systemctl管理Tomcat,并设置开机启动
本文转载:http://blog.chinaunix.net/uid-24648266-id-5729891.html CentOS7开始,从/etc/init.d脚本改为了systemctl管理服务 ...
- linux(centos)设置tomcat开机启动
方法一: linux 下tomcat开机自启动修改Tomcat/bin/startup.sh 为: export JAVA_HOME=/usr/java/j2sdk1.4.2_08 export CL ...