- 实体定义文件
实体定义文件一般存放位置是在对应模块的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"/>
- 实体类型
- 普通实体
- <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>
- 视图实体
- <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 entity-name="FaultTransSumView" package-name="com.sunyard.cpsp.fault">
- <description>业务差错统计视图</description>
- <member-entity entity-alias="FT" entity-name="FaultTrans"></member-entity>
- <alias entity-alias="FT" name="faultTypeId" group-by="true"></alias>
- <alias entity-alias="FT" name="createdDate" group-by="true"></alias>
- <alias entity-alias="FT" name="cpspMsgId" col-alias="count" function="count"></alias>
- </view-entity>
- <datasource name="localmysql"
- helper-class="org.ofbiz.entity.datasource.GenericHelperDAO"
- field-type-name="mysql"
- check-on-start="true"
- add-missing-on-start="true"
- check-pks-on-start="false"
- use-foreign-keys="true"
- join-style="ansi-no-parenthesis"
- alias-view-columns="false" //如果使用上面的复合函数类型(红色背景标记) 此处需要改为alias-view-columns="true" 切记!
- drop-fk-use-foreign-key-keyword="true"
- table-type="InnoDB"
- character-set="utf8"
- collate="utf8_general_ci">
- <read-data reader-name="seed"/>
- <read-data reader-name="seed-initial"/>
- <read-data reader-name="demo"/>
- <read-data reader-name="ext"/>
- <read-data reader-name="ext-test"/>
- <read-data reader-name="ext-demo"/>
- <inline-jdbc
- jdbc-driver="com.mysql.jdbc.Driver"
- jdbc-uri="jdbc:mysql://localhost/app_center?autoReconnect=true&characterEncoding=UTF-8"
- jdbc-username="root"
- jdbc-password="root"
- isolation-level="ReadCommitted"
- pool-minsize="2"
- pool-maxsize="250"
- time-between-eviction-runs-millis="600000"/>
- <!-- Please note that at least one person has experienced a problem with this value with MySQL
- and had to set it to -1 in order to avoid this issue.
- For more look at http://markmail.org/thread/5sivpykv7xkl66px and http://commons.apache.org/dbcp/configuration.html-->
- <!-- <jndi-jdbc jndi-server-name="localjndi" jndi-name="java:/MySqlDataSource" isolation-level="Serializable"/> -->
- </datasource>
- 扩展实体
- <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>
- 动态实体
- 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
- );
- 普通实体
- 实体定义
- 命名规则
实体名称(entity-name)首字母大写,如果实体名称由多个关键字组成,那么关键字首字母大写,例如entity-name="TenantDataSource",ofbiz 会在创建数据库表的时候根据entity-name 实体名称除首字母之外的大写字母前加“_”,所以entity-name="TenantDataSource"生成的数据库表名为 “Tenant_Data_Source”.
所以要控制entity-name 实体名称不要超过25个字母。
Field 表字段,命名规则与实体名称差不多,唯一不同的是首字母小写。 - 实体与数据库的关联
- <entity-group group="org.ofbiz.olap" entity="SalesInvoiceItemFact"/>
- <entity-group group="org.ofbiz.olap" entity="SalesInvoiceItemStarSchema"/>
也许你会发现并不是每个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>
- <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>
总结一下:我们通过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>
在启动各个应用模块的时候,系统会根据web.xml 中的 entityDelegatorName 生成delegator 对象,然后将delegator 对象存放到servletContext 中备用。
我们就是使用这个delegator对象执行数据库操作,以后会介绍如何使用。
- delegator = DelegatorFactory.getDelegator(delegatorName);
- servletContext.setAttribute("delegator", delegator);
- no-auto-stamp
no-auto-stamp="false"
entity 属性之一: 将此值设置为true , 则创建数据库表时将来不创建lastUpdatedStamp、lastUpdatedTxStamp、createdStamp、createdTxStamp 这四个字段。 - Field.type
- <field name="tenantId" type="id-ne"/>
%ofbiz_home%\framework\entity\fieldtype\fieldtypeXXX.xml 其中XXX为你使用的数据库名称。
- <field-type-def type="email" sql-type="VARCHAR(255)" java-type="String"/>
- prim-key
- <prim-key field="agreementId"/>
实体支持组合主键,即一个实体定义中可以有多个prim-key节点。
如果不定义主键的话,数据库是不会创建表的。 - 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 返回一个实体对象。
- index
- <index name="WEFF_KWD_KWD" unique="false">
- <index-field name="keyword" function="lower"/>
- </index>
: name 给索引起个别名。
: unique 是否唯一索引。
: index-field
: name 对实体哪个字段创建索引
: function 待确定。
- 命名规则
- 定义视图实体
- member-entity
- <member-entity entity-alias="EMPPOS" entity-name="EmplPosition"/>
- <member-entity entity-alias="EMPPOSFUL" entity-name="EmplPositionFulfillment"/>
entity-name实体名称
entity-alias实体别名。
实体定义顺序很重要,除了第一个实体之外其他都是被关联实体。 - 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"/>
entity-alias为实体别名,指当前字段是哪个实体的,
field实体字段名称,name字段别名。
group-by依据当前字段进行group-by 分组查询。
function对当前字段执行function 函数处理 。
- alias-all
- <alias-all entity-alias="ODD" prefix="orderDate" group-by="true">
- <exclude field="dimensionId"/>
- </alias-all>
exclude 将实体中某些字段剔除出去。 - 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>
而view-link 用来做 join 关联查询。
在entityengine.xml中<datasource ..>元素当中的join-style属性当中设置你的数据库join语法。
: rel-optional:关联类型,默认是内连接,如果将此属性值设为true ,则为外连接 - entity-condition
- <entity-condition>
- <order-by field-name="sequenceId"/>
- </entity-condition>
- 复杂字段
- <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')))
- member-entity