Hybris Model

基本 Model

hybris 有2个基础的Model

1.generation Model类,hybris  Commerce Suite 编译时完成

2.Model 生命周期,在hybris  Commerce Suite 运行时体现

Model Class Generation

在构建hybris系统时,构建框架为每个项目生成模型类和配置文件类型。Models的构建体现了所有的扩展,不论这个扩展是否扩能是否可用的在源码包或者二进制包中。Model构建过程中忽略了扩展

extensioninfo.xml配置文件中generated属性 <coremodule>的值。

Model自动构建到bootstrap/gensrc位置

 

生成任何一种类型的Model,都遵循下面的规则:

  1.model的名称为生成的类型加上Model后缀。比如,生成Product 的Model名称为ProductModel

  2.还将为Model生成一个类似的包名:

    字符串model 将最为包名的一部分被加到扩展的跟节点后面,而jalo 将被从包名中去除

    例如:de.hybris.platform.europe1.jalo.TaxRow 对应的Model为 de.hybris.platform.europe1.model.TaxRowModel.

   3.所有属性类型都是private的

 4.会自动为所有的属性创建getter,setter方法

在hybris系统构建的过程中非常早期的时候Models就已经生成了。

Tip

更早的检查Data Model

  Models 的创建都是依赖items.xml文件的,是匹配的。所以我们可以依赖 items.xml来检查创建的Model,这可以比在hmc中updating or initializing更早的发现问题。下面是个例子

<itemtype
  generate="true"
  code="ContactRequest"
  jaloclass="de.hybris.springmvcdemo.jalo.ContactRequest"
  extends="GenericItem"
  autocreate="true"
  >
    <attributes>
      <attribute qualifier="message" type="java.lang.String">
        <persistence type="property"/>
      </attribute>
    </attributes>
</itemtype>

platform 的modelclasses 文件夹生成的Model 类如下:

package de.hybris.springmvcdemo.model;
 
import de.hybris.platform.core.model.ItemModel;
 
/**
 * Generated Model class for type ContactRequest first defined at extension *springmvcdemo*
 */
@SuppressWarnings("all")
public class ContactRequestModel extends ItemModel
{
    /** <i>Generated type code constant.</i>*/
    public final static String _TYPECODE = "ContactRequest";
     
    /** 
         * <i>Generated constant</i> - Attribute key of <code>ContactRequest.message</code> attribute defined 
         * at extension <code>springmvcdemo</code>. 
         */
    public static final String MESSAGE = "message";
     
     
    /** <i>Generated variable</i> - Variable of <code>ContactRequest.message</code> attribute defined 
         * at extension <code>springmvcdemo</code>.
         */
    private String _message;
     
     
    /**
     * <i>Generated constructor</i> - for all mandatory attributes.
     * @deprecated Since 4.1.1 Please use the default constructor without parameters
     */
    @Deprecated
    public ContactRequestModel()
    {
        super();
 
    }
     
    /**
     * <i>Generated constructor</i> - for all mandatory and initial attributes.
     * @deprecated Since 4.1.1 Please use the default constructor without parameters
     * @param _owner initial attribute declared by type <code>Item</code> at extension <code>core</code>
     */
    @Deprecated
    public ContactRequestModel(final ItemModel _owner)
    {
        super(
            _owner
        );
 
    }
     
     
    /**
     * <i>Generated method</i> - Getter of the <code>ContactRequest.message</code> attribute defined 
         * at extension <code>springmvcdemo</core>. 
     * @return the message
     */
    public String getMessage()
    {
        if( !isAttributeLoaded(MESSAGE))
        {
          this._message = getAttributeProvider() == null ? null : (String) getAttributeProvider().getAttribute(MESSAGE);
          getValueHistory().loadOriginalValue(MESSAGE, this._message);
        }
        throwLoadingError(MESSAGE);
        return this._message;
    }
     
    /**
     * <i>Generated method</i> - Setter of <code>ContactRequest.message</code> attribute defined 
         * at extension <code>springmvcdemo</code>. 
     *  
     * @param value the message
     */
    public void setMessage(final String value)
    {
        this._message = value;
        markDirty(MESSAGE);
    }
     
}

Modifying the Model Generation

Models中的属性都是默认基于配置中的属性自动生成getter,setter方法。你可以在生成的过程中指定不需要哪个属性,或者执行所有的属性都不要那么就不会生成这个type对应的Model

  1. 排除所有的属性

<itemtype
  generate="true"
  code="ContactRequest"
  ...  >
    <model generate="false"/>
    <attributes>...</attributes>
</itemtype>

 2.如果要排除某一个属性,你必须明确定义它。这样无论的数private 属性还是getter,setter方法都不会有这个属性。配置方法是在 items.xml这个属性里添加 <model generate="false" />。如下:

<attribute qualifier="message" type="java.lang.String">
  <persistence type="property"/>
  <model generate="false"/></attribute>

生成的model构造函数如下:

/**
 * <i>Defined constructor from items.xml</i>
 * @param _message mandatory attribute declared by type <code>ContactRequest</code> at 
 * extension <code>impex</code>
 */
public ContactRequestModel(final String _message)
{
    super();
    setMessage(_message);
}

从4.2.2之后可以指定为属性生成的getter,setter方法

<attribute qualifier="message" type="java.lang.String">
  <persistence type="property"/>
  <model>
    <getter name="myMessage"/>
  </model></attribute>

在Model中对应的生成的getter方法getMyMessage() 如下

public String getMessage()
{
  ...
}
 
public String getMyMessage()
{
  return this.getMessage();
}

此外,你还可以通过指定的getter,setter方法作为默认的getter,setter方法

<attribute qualifier="message" type="java.lang.String">
  <persistence type="property"/>
  <model/>
    <getter name="myMessage" default="true"/>
  </model></attribute>

 生成了getMyMessage 方法,而原来的getMessage 方法没有了

public String getMyMessage()
{  // now executes logic of former getMessage() method  ...
}

还有标记生成的getter,setter方法为过期的

<attribute qualifier="message" type="java.lang.String">
  <persistence type="property"/>
  <model/>
    <getter name="myMessage" default="deprecated"/>
  </model></attribute>

生成的getMyMessage 方法被添加上了@deprecated 注解

public String getMessage()
{
  ...
}
/**
 * @deprecated use {@link #getMessage()} instead
 */
@Deprecated
public String getMyMessage()
{
  return this.getMessage();
}


Lazy Loading

惰性加载是在实例化对象的时候不是立刻就设置对象的全部属性值。Model的加载原理就是惰性加载

  一旦你加载一个Model,他包含所有的原始值。然而,在这种状态下,关系还未填写。一旦你通过调用相应的getter访问这样一种关系,这种关系是按需加载。这意味着一旦你加载一个模型,你需要担心加载任何依赖模型。

  在hybris 5.0。当加载模型,Model value是不加载的。Model只是一个空的java实例,没有设置任何值。 All Model values are only loaded when any value of the Model is retrieved。这种机制在Model初始化时可以提高性能

  如果要改变这种机制,在你的local.properties配置文件中设置 servicelayer.prefetch all or literal。literal 只会预加载原子属性的值,而不会加载引用的其他对象属性。

不建议设置all的加载机制,可能会出现循环依赖导致堆栈溢出错误。


Lazy Loading Model Relations

因为按需加载模型的关系,在某些情况下避免调用getter和setter方法。观察下面这个简单的例子和2中方式。统计一个用户的总金额

 

在服务层根据用户的订单来累计总金额。使用User Model的getOrders() 方法可以迭代所有的订单,再来统计总金额。我们知道现在场景下数据量是很小的。

...
public Double getTotal(UserModel user ) {
   double cumulativeTotalPrice = 0.0d;
   for (final OrderModel order : user.getOrders())
   {
      cumulativeTotalPrice += order.getTotalPrice().doubleValue();
   }
}
...

但是,想想如果是订单数据量很大的场景呢。比如,B2B商城,可能一个厂商只用了一个用户。第一次调用getOrders()返回这个用户的所有的 相关订单,理想情况下,结果都会被缓存起来。但是糟糕的情况是,执行查询并返回成千上万的订单行。查询结果中的每一行,订单模型实例化,然后缓存。

 

另一种方式是在DAO层使用FlexibleSearch 查询。查询汇总每个订单的总价格为单个结果只有一行被从数据库获取:

public Double getTotal() 
{
    final FlexibleSearchQuery fq = new FlexibleSearchQuery("SELECT SUM(totalPrice) AS CUMULATIVE_PRICE FROM {Order} WHERE {user} = ?session.user");
    fq.setResultClassList(Lists.newArrayList(Double.class));
 
    final SearchResult<Double> search = fs.search(fq);
    final List<Double> result = search.getResult();
    if (!result.isEmpty())
    {
        return result.iterator().next();
    }
     
    return Double.valueOf(0);
}


Model Context

一旦你加载一个模型或通过modelService创建它,就会放入Model 的上下文。Model context会跟踪Model 的所有变化,尤其是引用的新的还没有保存的Model

如果选择单独的保存Model,注意只有没有保存的Model会自动保存。已经创建的Model是不会保存的。

比如,你现在有一个CategoryModel对象,这个对象持有ProductModel对象,你修改了CategoryModel:

  • 如果ProductModel是新建的还没有保存的,那么保存CategoryModel对象的时候同样会保存ProductModel。

    这是因为ProductModel是一个新的对象,并且新的引用会保存

  • 如果ProductModel已经保存过,再次保存CategoryModel的时候ProductModel不会再保存了

    这是因为引用的对象ProductModel是已经存在的Model,存在的Model不会再次保存

因为Model context 会跟踪你的所有操作,可以保存所有的更改。你不需要单独保存每个模型。你可以一次保存所有的Model.关于怎么保存Model,请参考 Saving a Model 小节

如果你是用构造方法新建了一个Model,那么Model不会放入Model Context中。参见下面 Using a Constructor小节

 

你可以手工的为Model修改Model context

  • 把一个Model加入context:

modelService.attach(model)
  • 从context里删除一个Model:

modelService.detach(model)

Model context 绑定在HybrisRequestScope上,类似于标准的request作用域但是只作用于一个线程

当作用的session或者request呗关闭或者超时Model context会自动清除相关Model.所以可以判断,一个没有保存的Model被删除并不会影响线程的内存泄露

Model的创建或者修改储存在context中,如果你从数据库加载这样的模型,例如通过使用 flexible search,你得到同样的模型的实例存储在上下文。你必须意识到这种作坊是不能保证加载未修改的模型。如果你尝试展示2次在没有修改的前提下,你会得到 相同的对象,但是你不能依赖这个。最好的做法是在你的代码里持续保持对这个对象的引用。

记住Model context是线程本地的并且Model不是线程安全的。如果Model是多线程使用的情况需要对Model做同步处理。可以使用SessionService

最好不要使用事物回滚后的Model context。如果你要在事物回滚期间保存Models,可能会出错。这取决于你的使用模式。这是因为Model可能与他们的数据库表示处于不一致的状 态。比如要保存一个Model,他的主键已经生成但是因为回滚操作这个Model并没有被保存。因此不要使用事物回滚后的Model做检索或者创建




























你可能感兴趣的:(Hybris Model)