ofbiz之 entity 實體解析

ofbiz 之entity實體
1. 實體定義文件
實體定義文件一般存放位置是在對應模塊的entity文件夾下面,以party爲例,party的實體定義文件路徑爲%ofbiz-home%\applications\party\entitydef\entitymodel.xml。
通過對應模塊的ofbiz-component.xml進行加載。
   <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel.xml"/>
<entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel_old.xml"/>
實體定義文件可以爲多個。
2. 實體類型
2.1. 普通實體
<entity entity-name="TenantDataSource" package-name="org.ofbiz.entity.tenant">
        <description>
            There should be one record for each tenant and each group-map for the active delegator.
            The jdbc fields will override the datasource -> inline-jdbc values for the per-tenant delegator.
        </description>
        <field name="tenantId" type="id-ne"/>
        <field name="entityGroupName" type="name"/>
        <field name="jdbcUri" type="long-varchar"/>
        <field name="jdbcUsername" type="long-varchar"/>
        <field name="jdbcPassword" type="long-varchar"></field>
        <prim-key field="tenantId"/>
        <prim-key field="entityGroupName"/>
        <relation type="one" fk-name="TNTDTSRC_TNT" rel-entity-name="Tenant">
        <key-map field-name="tenantId"/>
        </relation>
</entity>
普通實體和數據庫中的表是一一對應的。程序會根據實體定義在數據庫中創建表,索引,外鍵約束等。
2.2. 視圖實體
<view-entity entity-name="WorkEffortAssocView"
            package-name="org.ofbiz.workeffort.workeffort"
            title="Work Effort Association Entity with Name">
      <member-entity entity-alias="WA" entity-name="WorkEffortAssoc"/>
      <member-entity entity-alias="WETO" entity-name="WorkEffort"/>
      <alias-all entity-alias="WA"/>
      <alias entity-alias="WETO" name="workEffortToName" field="workEffortName"/>
      <alias entity-alias="WETO" name="workEffortToSetup" field="estimatedSetupMillis"/>
      <alias entity-alias="WETO" name="workEffortToRun" field="estimatedMilliSeconds"/>
      <alias entity-alias="WETO" name="workEffortToParentId" field="workEffortParentId"/>
      <alias entity-alias="WETO" name="workEffortToCurrentStatusId" field="currentStatusId"/>
      <alias entity-alias="WETO" name="workEffortToWorkEffortPurposeTypeId" field="workEffortPurposeTypeId"/>
      <alias entity-alias="WETO" name="workEffortToEstimatedStartDate" field="estimatedStartDate"/>
      <alias entity-alias="WETO" name="workEffortToEstimatedCompletionDate" field="estimatedCompletionDate"/>
      <alias entity-alias="WETO" name="workEffortToActualStartDate" field="actualStartDate"/>
      <alias entity-alias="WETO" name="workEffortToActualCompletionDate" field="actualCompletionDate"/>
      <view-link entity-alias="WA" rel-entity-alias="WETO">
        <key-map field-name="workEffortIdTo" rel-field-name="workEffortId"/>
      </view-link>
      <relation type="one-nofk" fk-name="WK_EFFRTASSV_FWE" title="From" rel-entity-name="WorkEffort">
        <key-map field-name="workEffortIdFrom" rel-field-name="workEffortId"/>
      </relation>
</view-entity>
View entity 一般用做多表連接複雜查詢,view entity 不會在數據庫中反映出來。
2.3. 擴展實體
<extend-entity entity-name="UserLogin">
        <field name="partyId" type="id"></field>
        <relation type="one" fk-name="USER_PARTY" rel-entity-name="Party">
            <key-map field-name="partyId"/>
        </relation>
        <relation type="one-nofk" rel-entity-name="Person">
            <key-map field-name="partyId"/>
        </relation>
        <relation type="one-nofk" rel-entity-name="PartyGroup">
            <key-map field-name="partyId"/>
        </relation>
</extend-entity>
繼承已存在的實體並對其進行擴展。
2.4. 動態實體
DynamicViewEntity salesUsageViewEntity = new DynamicViewEntity();
            salesUsageViewEntity.addMemberEntity("OI", "OrderItem");
            salesUsageViewEntity.addMemberEntity("OH", "OrderHeader");
            salesUsageViewEntity.addMemberEntity("ItIss", "ItemIssuance");
            salesUsageViewEntity.addMemberEntity("InvIt", "InventoryItem");
            salesUsageViewEntity.addViewLink("OI", "OH", Boolean.valueOf(false), ModelKeyMap.makeKeyMapList("orderId"));
            salesUsageViewEntity.addViewLink("OI", "ItIss", Boolean.valueOf(false), ModelKeyMap.makeKeyMapList("orderId", "orderId", "orderItemSeqId", "orderItemSeqId"));
            salesUsageViewEntity.addViewLink("ItIss", "InvIt", Boolean.valueOf(false), ModelKeyMap.makeKeyMapList("inventoryItemId"));
    salesUsageViewEntity.addAlias("OI", "productId");
    salesUsageViewEntity.addAlias("OH", "statusId");
    salesUsageViewEntity.addAlias("OH", "orderTypeId");
    salesUsageViewEntity.addAlias("OH", "orderDate");
    salesUsageViewEntity.addAlias("ItIss", "inventoryItemId");
    salesUsageViewEntity.addAlias("ItIss", "quantity");
salesUsageViewEntity.addAlias("InvIt", "facilityId");
EntityListIterator salesUsageIt = delegator.findListIteratorByCondition(salesUsageViewEntity,
EntityCondition.makeCondition(
UtilMisc.toList(
         EntityCondition.makeCondition("facilityId", EntityOperator.EQUALS, facilityId),
          EntityCondition.makeCondition("productId", EntityOperator.EQUALS, productId),
            EntityCondition.makeCondition("statusId", 
EntityOperator.IN, 
UtilMisc.toList("ORDER_COMPLETED", "ORDER_APPROVED", "ORDER_HELD")),
        EntityCondition.makeCondition("orderTypeId", EntityOperator.EQUALS, "SALES_ORDER"),
           EntityCondition.makeCondition("orderDate", EntityOperator.GREATER_THAN_EQUAL_TO, checkTime)
),
EntityOperator.AND),null, null, null, null
);
在程序中手動創建實體,對其進行查詢。
3實體定義
3.1. 命名規則
實體名稱(entity-name)首字母大寫,如果實體名稱由多個關鍵字組成,那麼關鍵字首字母大寫,例如entity-name="TenantDataSource",ofbiz 會在創建數據庫表的時候根據entity-name 實體名稱除首字母之外的大寫字母前加“_”,所以entity-name="TenantDataSource"生成的數據庫表名爲“Tenant_Data_Source”.
所以要控制entity-name 實體名稱不要超過25個字母。
Field 表字段,命名規則與實體名稱差不多,唯一不同的是首字母小寫。
3.2. 實體與數據庫的關聯
    <entity-group group="org.ofbiz.olap" entity="SalesInvoiceItemFact"/>
<entity-group group="org.ofbiz.olap" entity="SalesInvoiceItemStarSchema"/>
Entity-group(一般定義在各個模塊的\entitydef\entitygroupXXX.xml中) 對實體進行分組,使不同的實體分屬不同的entity-group。
也許你會發現並不是每個entity都進行了entity-group 分組。事實上如果你沒有對實體進行分組歸類的話,系統啓動的時候他會將實體默認歸類到"org.ofbiz"中。
查看數據庫定義文件%ofbiz_home%/framework/entity/config/entityengine.xml
可以發現:
<delegator name="default" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main" distributed-cache-clear-enabled="false">
        <group-map group-name="org.ofbiz" datasource-name="localderby"/>
        <group-map group-name="org.ofbiz.olap" datasource-name="localderbyolap"/>
        <group-map group-name="org.ofbiz.tenant" datasource-name="localderbytenant"/>
</delegator>
可以發現delegator 將多個group-name組織到一起並將group-name與datasource-name對應起來,datasource-name又是什麼?通過查看 entityengine.xml 我們可以發現:
<datasource name="localderby"
            helper-class="org.ofbiz.entity.datasource.GenericHelperDAO"
            schema-name="OFBIZ"
            field-type-name="derby"
            check-on-start="true"
            add-missing-on-start="true"
            use-pk-constraint-names="false"
            use-indices-unique="false"
            alias-view-columns="false"
            use-order-by-nulls="true">
        <read-data reader-name="seed"/>
        <read-data reader-name="seed-initial"/>
        <read-data reader-name="demo"/>
        <read-data reader-name="ext"/>
        <inline-jdbc
                jdbc-driver="org.apache.derby.jdbc.EmbeddedDriver"
                jdbc-uri="jdbc:derby:ofbiz;create=true"
                jdbc-username="ofbiz"
                jdbc-password="ofbiz"
                isolation-level="ReadCommitted"
                pool-minsize="2"
                pool-maxsize="250"
                time-between-eviction-runs-millis="600000"/>
</datasource>
Datasource定義了數據庫驅動,數據庫用戶名、密碼等,所以datasource就是我們說的數據庫。 
總結一下:我們通過entity-group將各個實體和數據庫之間關聯起來,然後再將一個或多個數據庫歸屬到一個delegator 中,那我們又是怎麼使用數據庫進行數據庫操作的呢??查看每個模塊應用底下的web.xml 我們可以發現:
<context-param>
        <param-name>entityDelegatorName</param-name>
        <param-value>default</param-value>
        <description>The Name of the Entity Delegator to use, defined in entityengine.xml</description>
</context-param>
針對不同的應用,我們可以使用不同的delegator .如果不定義則使用default.
在啓動各個應用模塊的時候,系統會根據web.xml 中的 entityDelegatorName 
生成delegator 對象,然後將delegator 對象存放到servletContext 中備用。
我們就是使用這個delegator對象執行數據庫操作,以後會介紹如何使用。
delegator = DelegatorFactory.getDelegator(delegatorName);
    servletContext.setAttribute("delegator", delegator);


3.3. no-auto-stamp
no-auto-stamp="false"
entity 屬性之一: 將此值設置爲true , 則 創建數據庫表時將來不創建lastUpdatedStamp、lastUpdatedTxStamp、createdStamp、createdTxStamp
這四個字段。
3.4. Field.type
<field name="tenantId" type="id-ne"/>
Type , 將數據字段類型 與 java 類型關聯起來的設置。 定義文件路徑爲:
%ofbiz_home%\framework\entity\fieldtype\fieldtypeXXXXX.xml
其中XXXX爲你使用的數據庫名稱。
<field-type-def type="email" sql-type="VARCHAR(255)" java-type="String"/>
3.5. prim-key
<prim-key field="agreementId"/>
定義主鍵,其中field 需要是已經被定義過的字段,即field 定義過。
實體支持組合主鍵,即一個實體定義中可以有多個prim-key節點。
如果不定義主鍵的話,數據庫是不會創建表的。

3.6. relation
relation 定義當前實體和其他實體之間的關係,一般用做創建外鍵和根據關係查詢使用。
:rel-entity-name:被關聯實體名稱。
:fk-name:如果創建外鍵,那麼定義外鍵的名稱。
:title:給當前關係起個別名。
: field-name:當前實體的字段,指明當前實體的哪個字段與被關係實體有關係。
:rel-entity-name:被關係實體名稱
:rel-field-name:被關係的實體的字段名稱。指明field-name和被關係實體的哪個字段有關係。如果rel-field-name與field-name相同,那麼rel-field-name可以不定義。
:type="one-nofk":關聯類型,主要有三類 “one”、”one-nofk”、”many”
很多資料上將one 解釋爲 one-to-one ,將 many 解釋爲 one-to-many .
個人感覺不是很好理解,如果從數據庫方面去理解的話,one、one-nofk  的使用條件是被關係實體的rel-field-name爲主鍵,而many 的使用條件是被關係實體的rel-field-name爲非主鍵。而one 與 one-nofk 的區別在於one會在數據庫表結構中創建外鍵約束,而one-nofk 則不會。
Relation 除了用來創建外鍵約束之外還被用來做關係查詢。
當訪問關係的時候可以用 .getRelated("") 或者 .getRelatedOne("") 。用 title+entityName 作爲參數。
當實體一個"many"關係的時候使用getRelated 返回一個列表,當實體一個"one"關係的時候使用getRelatedOne 返回一個實體對象。

3.7. Index
<index name="WEFF_KWD_KWD" unique="false">
            <index-field name="keyword" function="lower"/>
</index>
創建索引。
: name:給索引起個別名。
: unique:是否唯一索引。
:index-field:name:對實體哪個字段創建索引,function待確定。
4. 定義視圖實體
4.1. Member-entity
<member-entity entity-alias="EMPPOS" entity-name="EmplPosition"/>
      <member-entity entity-alias="EMPPOSFUL" entity-name="EmplPositionFulfillment"/>
member-entity首先定義當前視圖實體可能會用到的實體。entity-name實體名稱
entity-alias實體別名。實體定義順序很重要,除了第一個實體之外其他都是被關聯實體。

4.2. alias
<alias entity-alias="EMPPOSFUL" name="partyId" field="partyId"/> 
    <alias entity-alias="EMPPOSFUL" name="emplPositionId" function="count"/>
<alias entity-alias="EMPPOSREPST" name="emplPositionIdReportingTo" group-by="true"/> 

Alias 定義當前視圖實體中會用到的字段。entity-alias爲實體別名,指當前字段是哪個實體的,field實體字段名稱,name字段別名。group-by依據當前字段進行group-by 分組查詢。function對當前字段執行function 函數處理 。
4.3. alias-all
<alias-all entity-alias="ODD" prefix="orderDate" group-by="true">
            <exclude field="dimensionId"/>
</alias-all>
alias-all 將某個實體的全部字段定義進來。Prefix定義以規定字段字符開頭的字段。
Exclude 將實體中某些字段剔除出去。

4.4. View-link
<view-link entity-alias="SOIF" rel-entity-alias="ODD" rel-optional="false">
    <key-map field-name="orderDateDimId" rel-field-name="dimensionId"/>
   </view-link>
視圖實體中relation 只能用來做關係查詢。
而view-link 用來做 join 關聯查詢。在entityengine.xml中<datasource ..>元素當中的join-style屬性當中設置你的數據庫join語法。
: rel-optional:關聯類型,默認是內連接,如果將此屬性值設爲true ,則爲外連接

4.5. Entity-condition
<entity-condition>
     <order-by field-name="sequenceId"/>
</entity-condition>
待定

4.6. 複雜字段
<alias entity-alias="OI" name="quantityOrdered" 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>
結果爲:
Select  SUM((COALESCE(OI.QUANTITY, 0) - COALESCE(OI.CANCEL_QUANTITY, 0))) 。。。。。。
一個缺省值是一個良好的習慣,否則當他們之中有一個爲空就會導致結果爲空
  這個操作可以支持你使用數據庫的所有函數例如  +, -, * 和 /,字符串連接符||。
你也可以添加一個 function="" 實現min, max, sum, avg, count, count-distinct, upper 和 lower 在 complex-alias-field中。比如:
<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>
結果爲SELECT (SUM(COALESCE(OI.QUANTITY,'0')) - SUM(COALESCE(OI.CANCEL_QUANTITY,'0')))

發佈了452 篇原創文章 · 獲贊 32 · 訪問量 93萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章