Interface ModelDataService
- All Superinterfaces:
Service
public interface ModelDataService extends Service
Provides APIs for reading and writing Models.
-
Method Summary
Modifier and Type Method Description <T extends Model>
longcount(java.lang.Class<T> clazz, PlatformUserContext context, SqlParams params, ModelFilter... filters)
This method is similar toread(Class, PlatformUserContext, SqlParams, ModelQueryComponent...)
with one key difference - it returns total count of models.java.util.Map<Model,java.util.Set<java.lang.String>>
getAvailableActions(java.util.Collection<? extends Model> models, PlatformUserContext context)
Given a collection of fully-populated Models (i.e.<T extends Model>
java.util.List<Field>getViewFilterFields(ViewRequest<T> viewRequest, PlatformUserContext context)
Returns a collection ofField
objects describing the required and optional filter fields available for the given view.<T extends Model>
java.util.List<T>read(java.lang.Class<T> topLevelClass, PlatformUserContext context, SqlParams params, ModelQueryComponent... queryComponents)
Reads Model objects from the database using user-provided filter, sort and retrieval criteria.<T extends Model>
java.util.List<ModelAudit<T>>readAudit(java.lang.Class<T> modelClass, PlatformUserContext ctx, SqlParams params, ModelQueryComponent... queryComponents)
Reads audit records for Models from the database using user-provided filter and sort criteria.<T extends Model>
TreadById(java.lang.Class<T> topLevelClass, java.lang.Long sysId, PlatformUserContext platformContext, ModelRetrieval... retrievals)
Convenience method for fetching a single Model by its surrogate id.<T extends Model>
java.util.Map<java.lang.Long,T>readByIds(java.lang.Class<T> topLevelClass, java.util.Collection<java.lang.Long> sysIds, PlatformUserContext platformContext, ModelRetrieval... retrievals)
Convenience method for fetching Models by surrogate id.<T extends Model>
java.util.Map<java.lang.Long,T>readByIds(java.lang.Class<T> topLevelClass, java.util.Collection<java.lang.Long> sysIds, java.util.Map<java.lang.Class<? extends Model>,java.util.Collection<java.lang.Long>> includeChildSysIdsByModelLevelType, PlatformUserContext platformUserContext)
Convenience method for fetching Models by ids and selecting which child model instances to fetch.<T extends Model>
java.util.List<T>readByView(ViewRequest<T> viewReadRequest, PlatformUserContext context)
Allows a client to programmatically invoke a view which was defined in studio.<T extends Model>
java.util.Set<java.lang.Long>validateReadPermission(java.lang.Class<T> topLevelClass, java.util.Set<java.lang.Long> sysIds, PlatformUserContext platformContext)
Given a Set of top-level model sys ids, executes a read query to check if the given context has access to those records.<M extends Model>
voidvalidateWritePermission(ModelWriteRequest<M> modelWriteRequest, PlatformUserContext platformContext)
Validates write permission for the given models without actually writing models in the DB.<M extends Model>
ModelList<M>write(ModelList<M> modelList, PlatformUserContext platformContext)
Create, update or delete models using Actions defined in the MPT or SPT.<M extends Model>
ModelList<M>write(ModelWriteRequest<M> modelWriteRequest, PlatformUserContext platformContext)
Create, update or delete models using Actions defined in the MPT or SPT.
-
Method Details
-
write
Create, update or delete models using Actions defined in the MPT or SPT. Given a ModelList containing the Models to be written to the database, executes the write action specified, then returns a list containing any Models whose write operation failed. For example, let's assume we want to insert a new Enterprise into the database. (Enterprise
is a common Platform model, defined in com.onenetwork.platform.common.)Enterprise enterprise = new Enterprise(); enterprise.setEntName("NewEnterprise"); ModelList<Enterprise> modelList = new ModelList<Enterprise>(EnterpriseActions.INSERT_OR_UPDATE, enterprise); ModelList<Enterprise> results = modelService.write(modelList, userContext); if (results.getErrors().size() > 0) { throw new Exception("Write failed: " + results.getErrors()); }
In the example above, we:- Instantiate a new model object in memory (Enterprise)
- Set all the properties of the model which we want updated in the database (in this case, we simply set the enterprise name)
- Create a new ModelList. For each of its arguments, we provide:
- action - EnterpriseActions.INSERT_OR_UPDATE. This is the name of the action we will invoke in the write operation.
Calls to write() are not simple DB updates; they are specific business actions which dictate their own validations,
workflows, state transitions, etc. Examples of action names could be things like PLACE_ORDER, CANCEL, etc.
EnterpriseActions is a generated class, containing all actions defined in the platform core - likewise, you will
have similar generated classes in your module for all actions you define in your MPT.
- model enterprise. This is the actual model(s) to be written. ModelList takes a varargs so you can pass in multiple. You can
also call getModels().add(...) after construction to add more.
- Write the list. The general contract of the write API is to return a new ModelList containing only those Models whose write operation failed (due to some business validation failure or other constraint). Thus the client should call results.getErrors() after the write to check for errors & respond appropriately.
Models can have ModelLink fields which refer to other Models in the system. For example, Organization has a ModelLink to its parent Enterprise. In the Organization object, this is represented with the following methods:- get/setEnterpriseName() - the Natural Key of the referenced Enterprise
- get/setSysEnterpriseId() - the Surrogate Key of the referenced Enterprise
Organization org = new Organization(); org.setName("MyOrg"); org.setEnterpriseName("MyEnt"); modelDataService.write(new ModelList<Organization>("PLT.InsertOrUpdate", org), userContext);
This will take the given natural key (MyEnt), lookup the corresponding surrogate id, and write both to the database. Alternately, you can write:Organization org = new Organization(); org.setName("MyOrg"); org.setSysEnterpriseId(10000L, true); modelDataService.write(new ModelList<Organization>("PLT.InsertOrUpdate", org), userContext);
This will do the opposite - given the surrogate id (10000), it will lookup the corresponding natural key and write both to the database. You will note that there is a boolean parameter in the surrogate id setter. This value specifes whether to nullify Natural Keys when setting the value. In order to ensure that the Natural and Surrogate ids don't get out of synch accidentally, any change to the Natural Key nullifies the Surrogate Id, and any change to the Surrogate Id requires a decision on the client's part as to whether or not to nullify the natural key. This supports both scenarios like the one above, where as a client we are trying to change the surrogate id and we don't know the natural key and don't want the responsibility of setting it, as well as the scenario where we might have both surrogate id and natural key in hand and want to set the NK and then SK, without losing the NK information. Changing Natural Keys
By default, no attempt will be made to change Natural Key fields when updating an existing model. (The surrogate id of the model is ignored for purposes of write.) If you want to change the Natural Key of the model, you should:- set the surrogate id of the model (setSysId()) to match the existing database value
- set the natural keys of the model to the new desired values
- use the
write(ModelWriteRequest, PlatformUserContext)
API, setting changeNaturalKeys to true on the model write request
When creating a list of models, the surrogate ids are written to each model instance, so when the write() call returns, you have access to them on the original instances. To get insight into the generated SQL and parameter bindings for calls to write(), you can set the following internal package to DEBUG in the logger:com.transcendsys.platform.server.trans.write.db
-
write
<M extends Model> ModelList<M> write(ModelWriteRequest<M> modelWriteRequest, PlatformUserContext platformContext)Create, update or delete models using Actions defined in the MPT or SPT. Similar towrite(ModelList, PlatformUserContext)
, but takes a ModelWriteRequest, which allows additional customization of the overall write operation, including whether to rollback all changes if one or more errors occurred, whether to return processed records in addition to error records, etc. To get insight into the generated SQL and parameter bindings for calls to write(), you can set the following internal package to DEBUG in the logger:com.transcendsys.platform.server.trans.write.db
- Parameters:
modelWriteRequest
- model write request which qualifies the write operationplatformContext
- callers' context- Returns:
- error results (or possibly all processed records, depending on the ModelWriteRequest)
-
readByIds
<T extends Model> java.util.Map<java.lang.Long,T> readByIds(java.lang.Class<T> topLevelClass, java.util.Collection<java.lang.Long> sysIds, PlatformUserContext platformContext, ModelRetrieval... retrievals)Convenience method for fetching Models by surrogate id. Map returned is keyed by surrogate id, with Model object as value. All model fields are fetched, and all children (recursively). Provide explicit retrievals to fetch only the selected children(s). To get insight into the generated SQL and parameter bindings for calls to readByIds(), you can set the following internal package to DEBUG in the logger:com.transcendsys.platform.server.trans.read.sql
- Parameters:
topLevelClass
- implementation class for the Model being read (for example,Enterprise
)sysIds
- collection of surrogate idsplatformContext
- caller's context- Returns:
- Map of surrogate id to Model
-
readByIds
<T extends Model> java.util.Map<java.lang.Long,T> readByIds(java.lang.Class<T> topLevelClass, java.util.Collection<java.lang.Long> sysIds, java.util.Map<java.lang.Class<? extends Model>,java.util.Collection<java.lang.Long>> includeChildSysIdsByModelLevelType, PlatformUserContext platformUserContext)Convenience method for fetching Models by ids and selecting which child model instances to fetch.- Parameters:
topLevelClass
- implementation class for the Model being read (for example,Enterprise
)sysIds
- collection of surrogate keys of top level modelincludeChildSysIdsByModelLevelType
- when provided, this is used as a filter to reduce the children returned; only children with these ids will be included. Please note that this means that a 3rd-level child's parent must also have its id included in order for that 3rd-level child to be returned. The Map should be keyed by ModelLevelType, with value of Collection of surrogate ids.platformContext
- caller's context- Returns:
- Map of surrogate id to Model
-
readById
<T extends Model> T readById(java.lang.Class<T> topLevelClass, java.lang.Long sysId, PlatformUserContext platformContext, ModelRetrieval... retrievals)Convenience method for fetching a single Model by its surrogate id. Model (including all children) is returned, or null if it isn't found. Provide explicit retrievals to fetch only the selected children(s).- Parameters:
topLevelClass
- implementation class for the Model being read (for example,Enterprise
sysIds
- surrogate idplatformContext
- caller's contextretrievals
- when provided, used as a filter to reduce the children returned;- Returns:
- Model, or null
-
read
<T extends Model> java.util.List<T> read(java.lang.Class<T> topLevelClass, PlatformUserContext context, SqlParams params, ModelQueryComponent... queryComponents)Reads Model objects from the database using user-provided filter, sort and retrieval criteria.
Assume one has a three-level Model, with levels House, Room and Furnishing. To retrieve all Houses from the database, one would use the following:List<House> houses = modelDataService.read(House.class, context, null);
Behind the scenes, the query would be formed as follows:- Since no explicit filter was given, all Houses in the database would be returned except Houses which the calling user doesn't have permission to (as dictated by the MPT and/or SPT).
- Since no explicit retrieval was given, all levels of House (House/Room/Furnishing) would be fetched. Thus if each House contains Rooms in the DB, those Rooms would be included in the getRooms() property of House. And if the Rooms contain Furnishings, those would be included in the getFurnishings() property of Room.
- Since no explicit sort was given, the results would be unsorted and could vary from call to call.
To retrieve only certain levels of the overall House model, one can provide explicit retrieval:import com.onenetwork.platform.data.model.ModelQuery; List<House> houses = modelDataService.read(House.class, context, null, ModelQuery.retrieve(Room.class));
In this case, only the Room level will be retrieved. Furnishings would be completely omitted, even if present in the database. Only key fields from House will be retrieved since it was not explicitly specified; all other fields will be left unset. To fetch both Room and Furnishing information (but without pulling all the details of the parent House) you would use the following:import com.onenetwork.platform.data.model.ModelQuery; List<House> houses = modelDataService.read(House.class, context, null, ModelQuery.retrieve(Room.class, Furnishing.class));
To filter the data using arbitrary SQL, you can use the ModelQuery.sqlFilter method. The following query will fetch only Houses built in the last year:List<House> houses = modelDataService.read(House.class, context, null, ModelQuery.sqlFilter("ZHSE_HOUSE.HOUSE_BUILT_DATE > systimestamp - 365"));
Additionally, you may want to provide bound parameters for portions of the queries. To achieve this,SqlParam
is used, and the rules of variable substition match those described in that class. For example:SqlParams params = new SqlParams(); params.setStringValue("BUILDER", "A%"); List<House> houses = modelDataService.read(House.class, context, params, ModelQuery.sqlFilter("ZHSE_HOUSE.BUILDER_NAME LIKE $BUILDER$"));
This would return all Houses whose builder name started with "A". You can combine multiple sqlFilters if desired ... these will be automatically AND'ed. Thus the previous example could also be written as:SqlParams params = new SqlParams(); params.setStringValue("BUILDER", "A%"); List<House> houses = modelDataService.read(House.class, context, params, ModelQuery.sqlFilter("ZHSE_HOUSE.HOUSE_BUILT_DATE > systimestamp - 365"), ModelQuery.sqlFilter("ZHSE_HOUSE.BUILDER_NAME LIKE $BUILDER$"));
If you want to combine the filters in ways other than AND, you should simply create one sqlFilter with the entire desired fragment. For example:SqlParams params = new SqlParams(); params.setStringValue("BUILDER", "A%"); List<House> houses = modelDataService.read(House.class, context, params, ModelQuery.sqlFilter("(ZHSE_HOUSE.HOUSE_BUILT_DATE > systimestamp - 365 and ZHSE_HOUSE.BUILDER_NAME LIKE $BUILDER$) or ZHSE_HOUSE.IS_DEMO_HOUSE = 1"));
To sort data, you can use the sqlSort method. The following query will order the houses by the date they were built, with more recent returned first:List<House> houses = modelDataService.read(House.class, context, null, ModelQuery.sqlSort("ZHSE_HOUSE.HOUSE_BUILT_DATE DESC"));
This can also include bound parameters, just like filters. For example, this will sort by the built date descending, but if that date is null, it will use "now" as the built date.SqlParams params = new SqlParams(); params.setTimestampValue("DEFAULT_BUILT_DATE", new java.sql.Timestamp(System.currentTimeMillis())); List<House> houses = modelDataService.read(House.class, context, null, ModelQuery.sqlSort("NVL(ZHSE_HOUSE.HOUSE_BUILT_DATE, $DEFAULT_BUILT_DATE$) DESC"));
You can also provide multiple sorts; these will be implicitly added in the order given. For example, the following will order by built date, followed by builder name as a secondary sort criteria.List<House> houses = modelDataService.read(House.class, context, null, ModelQuery.sqlSort("ZHSE_HOUSE.HOUSE_BUILT_DATE DESC"), ModelQuery.sqlSort("ZHSE_HOUSE.BUILDER_NAME"));
You can combine multiple sort, filter and retrieval as required, in any order. For example:SqlParams params = new SqlParams(); params.setStringValue("BUILDER", "A%"); params.setTimestampValue("DEFAULT_BUILT_DATE", new java.sql.Timestamp(System.currentTimeMillis())); List<House> houses = modelDataService.read(House.class, context, params, ModelQuery.sqlFilter("ZHSE_HOUSE.HOUSE_BUILT_DATE > systimestamp - 365"), ModelQuery.sqlFilter("ZHSE_HOUSE.BUILDER_NAME LIKE $BUILDER$"), ModelQuery.sqlSort("NVL(ZHSE_HOUSE.HOUSE_BUILT_DATE, $DEFAULT_BUILT_DATE$) DESC"), ModelQuery.retrieve(House.class, Room.class));
This query will retrieve Houses built in the last year with builder name starting with "A", order them by built date descending (using "now" as the default when the built date is null), and will return only Houses and Rooms (no Furnishings). Notice that the SqlParam bindings span across all filters/sort.
To set concurrencyVersion on retrieved model(s) and its children, you can use ModelQuery.concurrencyRetrieval() method.import com.onenetwork.platform.data.model.ModelQuery; List<House> houses = modelDataService.read(House.class, context, null, ModelQuery.concurrencyRetrieval());
In this case, a transient field named ConcurrencyVersion will be set for the retrieved houses and their retrieved child models. To get insight into the generated SQL and parameter bindings for calls to read(), you can set the following internal package to DEBUG in the logger:com.transcendsys.platform.server.model.read
- Type Parameters:
T
- type of the Model class being read- Parameters:
topLevelClass
- implementation class for the Model being read (for example,Enterprise
context
- caller's context (the models returned will be constrained by this user's permissions)params
- if the query requires bound params, this should contain those values - if it does not require params, pass nullqueryComponents
- query components, including filter, sort, retrieval, etc - acquired throughModelQuery
methods
-
count
<T extends Model> long count(java.lang.Class<T> clazz, PlatformUserContext context, SqlParams params, ModelFilter... filters)This method is similar toread(Class, PlatformUserContext, SqlParams, ModelQueryComponent...)
with one key difference - it returns total count of models.- Type Parameters:
T
- type of the Model class being read- Parameters:
clazz
- implementation class for the Model being read (for example,Enterprise
context
-params
- if the query requires bound params, this should contain those values - if it does not require params, pass nullfilters
-- Returns:
- total count of models in DB
-
readByView
<T extends Model> java.util.List<T> readByView(ViewRequest<T> viewReadRequest, PlatformUserContext context)Allows a client to programmatically invoke a view which was defined in studio. For example, below we read Books using a view "ZBKS.BooksByISBN", which takes a single String filter for the ISBN field:ViewRequest<Book> viewRequest = new ViewRequest<Book>(Book.class, "ZBKS.BooksByISBN"); viewRequest.addFilter(Book.class, "ISBN", "9880*"); List<Book> books = modelService.readByView(viewRequest, userContext);
- Type Parameters:
T
- type of the Model class being read- Parameters:
viewReadRequest
- describes the view being invoked, any filter values, etc.context
- caller's context (the models returned will be constrained by this user's permissions)- Returns:
- Models which are found by the given view invocation
-
readAudit
<T extends Model> java.util.List<ModelAudit<T>> readAudit(java.lang.Class<T> modelClass, PlatformUserContext ctx, SqlParams params, ModelQueryComponent... queryComponents)Reads audit records for Models from the database using user-provided filter and sort criteria. Similar toread(Class, PlatformUserContext, SqlParams, ModelQueryComponent...)
in many respects, but with some key differences:- Supports only "single level" queries.
- You may provide either a root model level or a child model level for the
modelClass
param. Only the given model level will be queried.ModelRetrieval
are not supported in thequeryComponents
param. If you query a child level, a ModelAudit wrapping the child level will be returned, and the child level model itself will have references to a parent Model object which is sparsely populated with only its NK and sys id. When querying a parent level, none of its children will ever be populated; you must make separate calls toreadAudit
to read the children. - Queries _ADT table
- The query will be executed against the _ADT table (e.g. ZBKS_BOOK_ADT instead of ZKBS_BOOK). Therefore,
any filter or sort criteria you provide must reference that explicitly, e.g.
sqlFilter("ZBKS_BOOK_ADT.CREATION_DATE > $CREATION_DATE$")
- Unpermissioned
- This is an unpermissioned read. It is up to the caller to ensure that audit records are not shared
with parties who should not see them (for example, by ensuring the model to which the audits are attached
is currently available via
readById(Class, Long, PlatformUserContext, ModelRetrieval...)
. This API returns all matching audits, regardless of permissions.
- Parameters:
modelClass
- model level to be queries. See description above to understand how parent/child relationships are handledctx
- caller's contextparams
- if the query requires bound params, this should contain those values - if it does not require params, pass nullqueryComponents
- query components, including filter, sort, etc - acquired throughModelQuery
methods. Does NOT supportModelRetrieval
.- Returns:
- one ModelAudit object per _ADT record matching the given filter criteria. if no sort order provided, will default sort by sysId desc, nvl(ptxDate, lastModifiedDate) desc, ptxVersion desc (i.e. grouped by sys id, with most recent changes first)
-
getViewFilterFields
<T extends Model> java.util.List<Field> getViewFilterFields(ViewRequest<T> viewRequest, PlatformUserContext context)Returns a collection ofField
objects describing the required and optional filter fields available for the given view.- Parameters:
viewRequest
- describes the viewcontext
- caller's context- Returns:
- available filter fields
-
getAvailableActions
java.util.Map<Model,java.util.Set<java.lang.String>> getAvailableActions(java.util.Collection<? extends Model> models, PlatformUserContext context)Given a collection of fully-populated Models (i.e. do not give stubs with sysId only), returns a Map of each Model to a Set containing the names of all Actions which are available to be executed on that model at this time by the calling context. The collection returned includes keys for all child models.- Parameters:
models
- Models for which to fetch actionscontext
- caller's context- Returns:
- Map of each Model to a Set containing the names of all Actions which are available to be executed on that model at this time by the calling context. The collection returned includes keys for all child models.
-
validateWritePermission
<M extends Model> void validateWritePermission(ModelWriteRequest<M> modelWriteRequest, PlatformUserContext platformContext)Validates write permission for the given models without actually writing models in the DB. If the model doesn't have write permission, error will be set on model. -
validateReadPermission
<T extends Model> java.util.Set<java.lang.Long> validateReadPermission(java.lang.Class<T> topLevelClass, java.util.Set<java.lang.Long> sysIds, PlatformUserContext platformContext)Given a Set of top-level model sys ids, executes a read query to check if the given context has access to those records. Returns a Set containing only those ids to which the given context has permissions.
-