`
jiasudu1649
  • 浏览: 719403 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

ofbiz实体引擎

阅读更多
ofbiz实体引擎
============================

* 保持你的实体名称少于25个字符
 
  甲骨文,举例来说,不喜欢表的名称长于30个字符,和ofbiz会添加一个“ _ ”表名与表名之间,这是保持他们短的最佳方式。

* 关系是如何工作的

  他们是被定义在entitymodel.xml文件的<entity>中

      <relation type="one" fk-name="PROD_CTGRY_PARENT" title="PrimaryParent" rel-entity-name="ProductCategory">
        <key-map field-name="primaryParentCategoryId" rel-field-name="productCategoryId"/>
      </relation>
      <relation type="many" title="PrimaryChild" rel-entity-name="ProductCategory">
        <key-map field-name="productCategoryId" rel-field-name="primaryParentCategoryId"/>
      </relation>
  type=定义类型的关系: "one" 是对于这个实体的关系一对一,"many" 是一对多。
  fk-name=是一个外键名。这是通常的良好做法,以设定自己的外键的名称,虽然ofbiz会自动生成如果它不在那里。
  相对实体名称=的名称是相关的实体。
  标题=是用来区分不同的关系时,有很多的关系,同样的两个实体。
  type= defines the type of the relationship: "one" for one-to-one or "many" for one-to-many from this entity
  fk-name= is a foreign key name.  It is usually good practice to set your own foreign key name, although OFBIZ will auto-generate if it's not there.
  rel-entity-name= 是相关的实体的名称。
  title= is used to distinguish different relationships when there are many relationships between the same two entities.

  <key-map> defines the fields for the relationship. field-name= is for the field of this entity to use.  If the field on the related entity
  has a different field name, then rel-field-name= defines the field name in the related entity.  You can have many fields serve as part of
  a key-map.

When you access a relationship, you would use .getRelated("") or .getRelatedOne("") with the title+entityName as parameter.  getRelated returns
a List and is appropriate when it is a "many" relation.  .getRelatedOne returns a single GenericVaue and is appropriate for "one" relations.

* A few things about view-entities

View-entities are very powerful and allow you to create join-like queries, even when your database doesn't support joins.

The configuration of your database's join syntax is in entityengine.xml under the join-style attribute of <datasource ..>

When you link two entities together using the <view-link ..> tag, remember
1.  The order of the entities you name is important.
2.  The default is an inner join (values must be present on both sides.)  To do an outer join, use rel-optional="true"

If several entities have the same field name, such as statusId, the one from the first entity will be used and the rest
tossed out.  So if you need the field from one, put its <alias-all> before the others.  Alternatively, use <alias ..> tag
to give the same field from different entities names, such as:
<alias entity="EntityOne" name="entityOneStatusId" field="statusId"/>
<alias entity="EntityTwo" name="entityTwoStatusId" field="statusId"/>

Another alternative is to use <exclude field=""> inside an <alias-all> as follows:
<alias-all entity-alias="EN">
  <exclude field="fieldNameToExclude1"/>
  <exclude field="fieldNameToExclude2"/>
</alias-all>
This top-down approach is more compact, which comes in handy for large tables.

Alternatively, you can specify one or more <exclude field="fieldName"> inside an <alias-all>.
This top-down approach is more compact than specifying the alias for every field in a big
table.

If you need to do a query like this
SELECT count(visitId) FROM ... GROUP BY trackingCodeId WHERE fromDate > '2005-01-01'
include field visitId with function="count", trackingCodeId with group-by="true", and fromDate with group-by="false"

Then **VERY IMPORTANT** when you do your query, such as delegator.findByCondition, you must specify the fields to select,
and you must not specify the field fromDate, or you will get an error.  This is why these view-entities can't be viewed
from webtools.

For an example, look at the view entities at the bottom of applications/marketing/entitydef/entitymodel.xml and
the BSH scripts in applications/marketing/webapp/marketing/WEB-INF/actions/reports.

* Do I have to define my view-entities in an entitymodel.xml file?

No, you can also define them dynamically.  A good example is the findParty method in org.ofbiz.party.party.PartyServices

* How to build conditions for expiration dates

There is a series of very helpful methods called EntityUtil.getFilterByDateExpr which return an EntityConditionList
to filter out search results by date. 

* How to work with large sets of data

If you need to select large sets of data, you should use the EntityListIterator instead of the List.  For example, if you did

List products = delegator.findAll("Product");

You may get yourself a "java.lang.OutOfMemoryError".  This is because findAll, findByAnd, findByCondition will try to retrieve all the records into
memory as a List.  In that case, re-write your query to do return an EntityListIterator then loop through it.  For example, this query can
be re-written as:

productsELI = delegator.findListIteratorByCondition("Product", new EntityExpr("productId", EntityOperator.NOT_EQUAL, null), UtilMisc.toList("productId"), null);

Note that the only method for finding an EntityListIterator is a by condition, so you would have to re-write your conditions as EntityExpr (in this case, a dummy
one which just says that productId is not null, which should apply to all Product entities, since productId is a not-null primary key field) or EntityConditionList.
This method also asks you to fill in the fields to select (in this case just productId) and order by (which I didn't specify with the last null.)

You can pass a null EntityCondition to grab all records.  However, this does not work across all databases!  Beware the use of avanced functionality such as the EntityListIterator with maxdb and other odd databases.

* How to use an EntityListIterator

When iterating through the EntityListIterator, this is the preferred form:

while ((nextProduct = productsELI.next()) != null) {
....
    // operations on nextProduct
}

Using the .hasNext() method on EntityListIterator is considered wasteful.

When you are done, don't forget to close it:

productsELI.close();

* How to do a select distinct

The only way we know of to do it with the entity engine is to find a list iterator and use EntityFindOptions to specify it, like this:
    listIt = delegator.findListIteratorByCondition(entityName, findConditions,
            null, // havingEntityConditions
            fieldsToSelectList,
            fieldsToOrderByList, 
           
            // This is the key part.  The first true here is for "specifyTypeAndConcur"
            // the second true is for a distinct select.  Apparently this is the only way the entity engine can do a distinct query
            new EntityFindOptions(true, EntityFindOptions.TYPE_SCROLL_INSENSITIVE, EntityFindOptions.CONCUR_READ_ONLY, true));

In minilang, curiously, it is much easier:
  <entity-condition entity-name="${entityName}" list-name="${resultList}" distinct="true">
     <select field="${fieldName}"/>
     ....

* How to do a case-insensitive search

You would need to make the find expressions convert both sides to uppercase, like this:
andExprs.add(new EntityExpr("lastName", true, EntityOperator.LIKE, "%"+lastName+"%", true));

(from org.ofbiz.party.party.PartyServices)

* How to go from EntityListIterator to just List

  Use the EntityListIterator.getCompleteList() and getPartialList methods

* How to get the next ID value automatically

  Use either <sequence-id-to-env ...> in minilang or delegator.getNextSeqId(...) in Java.  The id sequence numbers are stored in an
  entity SequenceValueItem.

* A word of warning about ID values

  DO NOT CREATE SEED OR DEMO DATA WITH ID 10000!  When the system tries to create more values automatically, it will also try to use 10000,
  resulting in a key clash.

* How to get a sequence ID of an item
 
  Some entities, like InvoiceItem and OrderItem, have an itemSeqId as well.  This can also be generated automatically for you by first making
  a GenericValue of the item, then asking the delegator to generate the item seq ID:

  GenericValue orderItem = delegator.makeValue("OrderItem", orderItemValues);
  delegator.setNextSubSeqId(orderItem, "orderItemSeqId", ORDER_ITEM_PADDING, 1);

* How to set up an alias that does the equivalent of SELECT SUM(QUANTITY - CANCEL_QUANTITY) AS QUANTITY

  <alias entity-alias="OI" name="quantity" function="sum">
      <complex-alias operator="-">
          <complex-alias-field entity-alias="OI" field="quantity" default-value="0"/>
          <complex-alias-field entity-alias="OI" field="cancelQuantity" default-value="0"/>
      </complex-alias>
  </alias>

  This results in SELECT SUM(COALESCE(OI.QUANTITY,'0') - COALESCE(0I.CANCEL_QUANTITY)) AS QUANTITY
  Including a default-value is a good habit, otherwise the result of the subtraction will be null if
  any of its fields are null.

  The operator can be any of the supported SQL operations of your database, such as arithmetic with
  +, -, * and / or concatenation of strings with ||.

  You can add a function="" to perform min, max, sum, avg, count, count-distinct, upper and lower
  on the complex-alias-field.  For example, an alternative way to express the query above is to do:

  <alias entity-alias="OI" name="quantity">
      <complex-alias operator="-">
          <complex-alias-field entity-alias="OI" field="quantity" default-value="0" function="sum"/>
          <complex-alias-field entity-alias="OI" field="cancelQuantity" default-value="0" function="sum"/>
      </complex-alias>
  </alias>

  Which results in SELECT (SUM(COALESCE(OI.QUANTITY,'0')) - SUM(COALESCE(OI.CANCEL_QUANTITY,'0'))) AS QUANTITY

* I hate the @#!$^_ OFBIZ Entity Engine.  Give me a JDBC connection!

  Ok, here's how you can get and use a JDBC connection:

import org.ofbiz.entity.jdbc.ConnectionFactory;

String helperName = delegator.getGroupHelperName("org.ofbiz");    // gets the helper (localderby, localmysql, localpostgres, etc.) for your entity group org.ofbiz
Connection conn = ConnectionFactory.getConnection(helperName);
Statement statement = conn.createStatement();
statement.execute("SELECT * FROM PARTY");
ResultSet results = statement.getResultSet();

// ... work with it as normal JDBC results

Alternatively, you can use the SQLProcessor like this:

SQLProcessor sqlproc = new SQLProcessor(helperName);
sqlproc.prepareStatement("SELECT * FROM PARTY");
ResultSet rs1 = sqlproc.executeQuery();

ResultSet rs2 = sqlproc.executeQuery("SELECT * FROM PRODUCT");

For an example, see framework/webtools/webapp/webtools/WEB-INF/actions/entity/EntitySQLProcessor.bsh

For javadoc please see:
http://www.opentaps.org/javadocs/version-1.0/framework/api/org/ofbiz/entity/jdbc/SQLProcessor.html
http://www.opentaps.org/javadocs/version-1.0/framework/api/org/ofbiz/entity/jdbc/ConnectionFactory.html

  *** THINK ABOUT THIS FIRST: You're giving up database independence and in some ways cutting yourself off
from the rest of the framework and the other applications.  Are you SURE you want to do this?

For a better way to do this, see http://www.opentaps.org/docs/index.php/Using_the_Query_Tool

* WARNING ABOUT COMPARING TIMESTAMPS

It seems that when you do a GREATER_THAN operation on a Timestamp, you will get the same Timestamp:

delegator.findByAnd("XXX", UtilMisc.toList(new EntityExpr("fromDate", EntityOperator.GREATER_THAN, "2007-12-31 23:59:59.998")));

will also get records with fromDate of 2007-12-31 23:59:59.998.  (This happened on PostgreSQL 8.1 and the GenericDAO class was generating 'FROM_DATE > ' so I'm not sure why
this happens.)  To be safe, add 1 second to the timestamp and use GREATER_THAN_EQUAL_TO

delegator.findByAnd("XXX", UtilMisc.toList(new EntityExpr("fromDate", EntityOperator.GREATER_THAN_EQUAL_TO, "2008-01-01 00:00:00.998")));

* WARNING: EntityOperator.IN on empty Lists

Be careful that your lists are not empty for EntityOperator.IN, or you might get a Syntax Error: FALSE from Derby and possibly other cryptic messages from other databases.
Always perform a UtilValidate.isNotEmpty on a retrieved List before using it in EntityOperator.IN

* WARNING: delegator.getNextSubSeqId does not guarantee uniqueness

There are many entities with composite or cyclic primary keys.  For example, OrderItem's primary key fields are orderId and orderItemSeqId.  InventoryItemDetail's primary key
fields are inventoryItemId and inventoryItemSeqId.  Usually, delegator.getNextSubSeqId is used to get the seq-id value, BUT IT MAY NOT GUARANTEE UNIQUENESS AGAINST MULTI-THREADED
ACCESS.  This issue is documented in http://issues.apache.org/jira/browse/OFBIZ-1636.

For now, if it is possible that several threads might try to write to an entity with composite keys, then use delegator.getNextSeqId instead of getNextSubSeqId.  (This is not the
case with OrderItem, where an order is typically written by just one thread, but it may happen with InventoryItemDetail, where multiple threads could create orders that try to
reserve inventory.)


applies to on
分享到:
评论
1 楼 dongbiying 2013-04-10  
  很强 。。。

相关推荐

    OFbiz实体引擎指南

    OFBiz是一个非常著名的电子商务平台,是一个非常著名的开源项目,提供了创建基于最新J2EE/XML规范和技术标准,构建大中型企业级、跨平台、跨数据库、跨...包括实体引擎, 服务引擎, 消息引擎, 工作流引擎, 规则引擎等。

    Ofbiz16.11.05运行及开发环境搭建等

    - **Ofbiz实体引擎(九) 多租户**:实体引擎支持多租户架构,允许在一个OFBiz实例上管理多个独立的业务环境,每个环境有自己的数据和配置。 - **Ofbiz权限判断语法**和**权限设计详解**:OFBiz具有精细的权限管理...

    ofbiz_springservice.zip

    基于spring封装的ofbiz所有服务,使用spring security进行安全验证,可以方便的发布为微服务,同时实现了一套直接使用ofbiz实体引擎操作ofbiz所有数据库表的spring应用框架设计

    ofbiz入门资料,全英文的

    #### 五、Apache OFBiz 实体引擎使用 - **实体定义**:实体通过 XML 文件定义其结构,包括字段名称、类型及关联关系等。 - **数据操作**:通过实体引擎提供的 API,可以轻松地对数据库中的实体进行增删改查操作。 - ...

    ofbiz数据结构设计

    通过灵活的实体模型、高效的实体引擎、丰富的服务层、流程化的业务处理、智能的缓存策略、适应性的数据分区以及严谨的安全机制,OFBiz提供了强大且灵活的数据管理能力,为企业信息化建设提供了有力支撑。在实际项目...

    OFBIZ开发指南 英文2

    实体引擎是OFBIZ中的数据管理部分,负责数据库操作。它提供了实体定义语言(Entity Definition Language, EDDL)用于描述业务对象,并支持实体-关系(ER)模型,使得数据操作更加灵活和高效。 事务处理引擎则处理...

    ofbiz学习笔记(自学整理)

    实体则代表业务对象,如产品、订单和客户,它们的定义存储在数据库模型中,并通过实体引擎进行操作。 在Ofbiz中,工作流系统允许定义和自动化业务流程,而事件处理系统则用于响应各种内部或外部事件,如定时任务或...

    ofbiz开发入门之CmsBackEnd实现的CRUD

    总结一下,OFBiz的CmsBackEnd CRUD实现涉及到与OFBiz核心组件的交互,尤其是实体引擎。开发者需要了解并熟练运用服务定义、实体操作以及查询语言,才能高效地完成内容管理任务。通过博客文章和提供的截图,学习者...

    Ofbiz数据模型查询手册

    在查询方面,手册将深入讲解如何利用Ofbiz的实体引擎(Entity Engine)进行高效的数据库查询。这可能包括使用EntityFinders、实体表达式语言(EntityExprs)以及SQL查询的自定义实现。此外,手册还会涉及事务管理和...

    ofbiz开源框架学习资料(附有小例子)

    - **设计模式**:在实体引擎中,OFBIZ采用了多种设计模式,如业务代理(Business Delegate)、值对象(Value Object)、复合实体(Composite Entity)、值对象组装器(Value Object Assembler)、服务定位器(Service ...

    OFBiz经典入门教程加速度编写

    1. **实体管理**:OFBiz使用实体引擎来处理数据模型,通过实体定义文件(.entity.xml)来创建和操作数据库表。 2. **服务开发**:服务引擎是OFBiz处理业务逻辑的核心,服务定义文件(.servicedef.xml)定义了服务的...

    OFBiz-技术文档

    1. **核心概念**:OFBiz的核心组件包括实体引擎、工作流引擎、事件驱动模型、服务引擎和安全模型。这些组件共同构成了一个灵活且可扩展的框架,使得开发者可以快速构建企业级应用。 2. **安装与配置**:文档可能...

    ofbiz中文技术文档

    5. **数据库模型**:Ofbiz基于实体引擎进行数据管理,文档可能会列出主要的实体关系图,帮助读者理解数据结构。 6. **国际化与本地化**:Ofbiz支持多语言环境,文档可能会讲解如何配置和实现中文环境。 7. **案例...

    原创 Ofbiz 入门教程

    接下来需要将自定义的`entitymodel_study.xml`文件集成到Ofbiz的实体引擎中。这一步骤需要在`entityengine.xml`文件中添加引用: ```xml &lt;!-- 在 entityengine.xml 文件中添加以下内容 --&gt; ``` 同时,...

Global site tag (gtag.js) - Google Analytics