OFBIZ ENTITY ENGINE COOKBOOK
============================
OFBIZ ENTITY ENGINE 菜單
* Keep your entity names less than 25 characters
Oracle, for example, does not like tables with names longer than 30 characters, and OFBIZ
will add a "_" between words, so it's best to keep them short.
* 保證讓你的entity names在25個字元以内
因為有些資料庫不允許表名超過30個字元,例如Oracle.而且ofbiz還要在單詞之間加入"_",是以盡可能的讓實體名稱短。
* How relationships work
如何建立關系
They are defined in entitymodel.xml files for an <entity> like this:
關系是在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= defines the type of the relationship: "one" for one-to-one or "many" for
one-to-many from this entity
type=定義了一個關系類型,從這個實體看來"one" 是one-to-one 或者"many"是one-to-many
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.
fk-name是一個外鍵名稱,最佳實踐政策是自己在這裡定義外鍵名稱,雖然如果這裡不寫OFBIZ會自動生成一個
rel-entity-name= is the name of the related entity.
rel-entity-name是被關聯實體名稱
title= is used to distinguish different relationships when there are many relationships between the same two entities.
title是用來在兩個實體之間存在多種關系的時候用來區分不同關系的名稱
<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.
<key-map> 為關系定義了字段
field-name是本實體用到的字段,如果在被關聯實體當中使用不同的字段名,那麼用rel-field-name定義被關聯實體當中的字段名,一個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.
當通路關系的時候可以用 .getRelated("") 或者 .getRelatedOne("") 用 title+entityName 作為參數。
當實體一個"many"關系的時候使用getRelated 傳回一個清單,當實體一個"one"關系的時候使用getRelatedOne 傳回一個GenericVaue .
* A few things about view-entities
關于view-entities的一些說明
View-entities are very powerful and allow you to create join-like queries, even when your database doesn't support joins.
view-entities是非常有用的并且允許你建立join-like查詢,甚至你的資料庫不支援joins都可以
The configuration of your database's join syntax is in entityengine.xml under the join-style attribute of <datasource ..>
在entityengine.xml中<datasource ..>元素當中的join-style屬性當中設定你的資料庫join文法
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"
當你将兩個實體連接配接在一起的時候使用 <view-link ..>标簽,記住
1. 實體名稱的順序很重要
2. 預設情況時内連接配接(值必須在兩邊都出現)如果要作一個外連接配接用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:
如果幾個實體擁有相同名稱的字段,例如statusId,那麼第一個實體的statusId被使用其它的都會抛棄掉,是以如果需要使用其它實體當中相同名字字段的時候,把它們放入<alias-all>,作為一個選擇用 <alias ..> 标簽
可以區分不同實體當中相同的名字字段,例如:
<alias entity="EntityOne" field="statusId"/>
<alias entity="EntityTwo" field="statusId"/>
Another alternative is to use <exclude field=""> inside an <alias-all> as follows:
另一個選擇就是在 <alias-all>内使用<exclude field="">例如
<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>.
更加簡潔的一種寫法是在<alias-all>當中使用<exclude field="fieldName">
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"
用function="count"包含字段visitId
,用group-by="true"給trackingCodeId,用fromDate給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.
非常非常重要的是當你查詢的時候,例如使用delegator.findByCondition,你必須指定選擇的字段,在上例中
不指定fromDate,你會得到一個錯誤,這也是為什麼view-entities為什麼不能在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.
* 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.
有一系列非常有用的方法叫 EntityUtil.getFilterByDateExpr 能夠傳回EntityConditionList用于通過日期實體條件。
* 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
如果你需要選擇大量的資料集合,你可以用EntityListIterator替代List.例如如果你做了
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:
你可能得到一個"java.lang.OutOfMemoryError"異常。這是因為findAll, findByAnd, findByCondition嘗試把所有的符合标準的紀錄加載到記憶體當中,一個解決方案是重新寫你的查詢作為一個EntityListIterator并且周遊它,例如上面的查詢可以寫為
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.)
注意這是唯一的一個通過條件得到一個EntityListIterator的方法,你必須用EntityExpr(這個例子當中表示為productId 不能為 null,其實是一句廢話,就是說明所有紀錄)或EntityConditionList者重寫你的條件 。這個方法也要求指定所有要選擇的字段(這個例子裡面隻有productId) 并且order by(在給出的例子當中沒有指定,位置位于最有一個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.
你可以通過一個空的EntityCondition 抓取所有紀錄,然而這種做法并不支援所有的資料庫,對于大型資料庫或者奇怪的資料庫,謹慎的使用進階的函數例如EntityListIterator當中的函數。
* How to use an EntityListIterator
如何使用一個EntityListIterator
When iterating through the EntityListIterator, this is the preferred form:
當周遊EntityListIterator的時候如下的做法是首選的
while ((nextProduct = productsELI.next()) != null) {
....
// operations on nextProduct
}
Using the .hasNext() method on EntityListIterator is considered wasteful.
在EntityListIterator 當中使用.hasNext()被認為是浪費資源的
When you are done, don't forget to close it:
當你使用EntityListIterator ,不要忘記關閉它
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:
據我們所知在 entity engine隻能通過指定EntityFindOptions 得到一個list iterator例如:
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:
奇怪的是在minilang他非常簡單。
<entity-condition entity-name="${entityName}" list-name="${resultList}" distinct="true">
<select field="${fieldName}"/>
....
* How to go from EntityListIterator to just List
怎樣從EntityListIterator變為一個純粹的List
Use the EntityListIterator.getCompleteList() and getPartialList methods
使用EntityListIterator.getCompleteList()和getPartialList方法
* How to get the next ID value automatically
怎樣通過自動增長得到下一個ID
Use either <sequence-id-to-env ...> in minilang or delegator.getNextSeqId(...) in Java. The id sequence numbers are stored in an entity SequenceValueItem.
使用在minilang中的<sequence-id-to-env ...> 或者 Java 中的delegator.getNextSeqId(...)這個id序列的數字被存儲在一個SequenceValueItem當中。
* A word of warning about ID values
關于ID值被警告的說明
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.
不要用ID 10000建立種子或者例子資料!當系統嘗試穿件自動增長的值時候他會嘗試10000
* How to set up an alias that does the equivalent of SELECT SUM(QUANTITY - CANCEL_QUANTITY) AS QUANTITY
怎樣設定一個别名類似于SELECT SUM(QUANTITY - CANCEL_QUANTITY) AS QUANTITY這用SQL語句
<alias entity-alias="OI" 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 ||.
給這個SELECT SUM(COALESCE(OI.QUANTITY,'0') - COALESCE(0I.CANCEL_QUANTITY)) AS QUANTITY的結果一個預設值是一個良好的習慣,否則當他們之中有一個為空就會導緻結果為空
這個操作可以支援你使用資料庫的所有函數例如 +, -, * 和 /,字元串連接配接符||。
You can add a function="" to perform min, max, sum, avg, count, count-distinct, upper and lower
你也可以添加一個 function="" 實作min, max, sum, avg, count, count-distinct, upper 和 lower on the complex-alias-field. For example, an alternative way to express the query above
is to do:
對于複雜的别名字段,例如在查詢中的二選一的表達式采用如下做法
<alias entity-alias="OI" >
<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
結果是類似 SELECT (SUM(COALESCE(OI.QUANTITY,'0')) - SUM(COALESCE(OI.CANCEL_QUANTITY,'0'))) AS QUANTITY的查詢結果
原文位址: http://blog.sina.com.cn/s/blog_6a61574d0100nkqe.html