I am using Google Cloud node.js gcloud library and trying to get an entity that was saved with ancestor key.
To my surprised, I am not able to get the entity without specifying its ancestor key.
const ds = gcloud.datastore.dataset(config);
...
ds.get(key, (err, entity)=>{
return entity;
});
The unique identifier for your entity is the full path, the id/name of the entity is not globally unique.
As an example, let's assume you were modelling a basic file system that has folders and files. Folders are the parent entities and files are the child entities. You might for example have data like:
File Entity: name='readme.txt', ancestor=['Folder', 'getting-started']
File Entity: name='readme.txt', ancestor=['Folder', 'third-party-libs']
Without specifying the ancestor, the system cannot disambiguate which 'readme.txt' you are trying to reference.
Related
I have a requirement to get products by code without knowing catalogType. Is that possible to retrieve products without passing catalogType?
Below is the code snippet I've tried:
#Resource
private ProductDao productDao;
#Resource
private CatalogVersionService catalogVersionService;
List<ProductModel> getProductsByCode(String code) {
CatalogVersionModel catalogVersionModel = new CatalogVersionModel();
catalogVersionModel.setVersion("Online");
catalogVersionService.addSessionCatalogVersion(catalogVersionModel);
List<ProductModel> productModels = productDao.findProductsByCode(code);
}
Below is the exception am getting:
{
"errors": [
{
"message": "model CatalogVersionModel (<unsaved>) cannot be serialized due to being modified, new or removed",
"type": "FlexibleSearchError"
}
]
}
May I know how to fix for above issue?
When you create a product/variant in SAP Commerce (hybris) you must attach it to a catalog.
A catalog (CatalogModel) also have a version (usually staged or online), and the object is called a CatalogVersionModel
When you want to retrieve a product/variant, you must indicate the CatalogVersionModel because the product code is not a unique key to retrieve the product in the DB (you can check the Type "Product" in the backoffice and see in the XML pane that both code and catalogVersion have the value unique="true")
Now in you code there are several issue.
You should not create a catalog version but you should retrive it using a service (See DefaultCatalogVersionService)
You should use a service to retrieve your product (See DefaultProductService)
In productService implementation, you'll find two methods getProductForCode.
One with only the sku code as parameter
One with the sku code and catalogVersion as parameter
The first method actually looks like the method you want, but in fact, it uses the catalogVersion in your session. Your session will be different if you run your code in groovy or if you run your code in Java from your ecommerce website.
You can find the comment of this method below
Returns the Product with the specified code. As default the search uses the current session user, the currentsession language and the current active catalog versions (which are stored at the session in the attribute SESSION_CATALOG_VERSIONS).For modifying the search session context see FlexibleSearchQuery.
You need to specify the catalog, because it is possible to have multiple catalogs, and the same product could exist in all of those catalogs.
I have a Cosmos DB with a container that contains document with varying structure.
I am using the Java SQL API for reading the documents from this container.
The issue I am having is that the API methods for querying/reading the container expects a model class as input param and will return instances of the model class. Because my container contains documents that have varying fields and depth, it is not possible for me to create a model class to represent this.
I need to be able to read/query the documents and then parse it myself and extract the values that I am looking for.
Any ideas? I have used "Object" in the API methods for e.g. queryItem and then it returns a LinkedHashMap that I can parse myself. Is this the way to do it? It looks a bit "raw" but I have not found a better way.
Below is a typical example from the SDK doc. I cannot create a "Family" model class in my code, because the structure can vary from document to document - both which fields are stored and the depth.
private void queryItems() {
CosmosQueryRequestOptions queryOptions = new CosmosQueryRequestOptions();
queryOptions.setQueryMetricsEnabled(true);
CosmosPagedIterable<Family> familiesPagedIterable = container.queryItems(
"SELECT * FROM Family WHERE Family.lastName IN ('Andersen', 'Wakefield', 'Johnson')", queryOptions, Family.class);
familiesPagedIterable.iterableByPage(10).forEach(cosmosItemPropertiesFeedResponse -> {
logger.info("Got a page of query result with {} items(s) and request charge of {}",
cosmosItemPropertiesFeedResponse.getResults().size(), cosmosItemPropertiesFeedResponse.getRequestCharge());
logger.info("Item Ids {}", cosmosItemPropertiesFeedResponse
.getResults()
.stream()
.map(Family::getId)
.collect(Collectors.toList()));
});
}
Per my understanding, it's determined by the sdk funtion's input parameters and output data type. And exactly, we can find that both sample code for java or spring are depends on the data model. So it's really good for you to use Object in your code because of the various documents.
And it's true that we can't design a data model to contain all the properties in the documents but I think it's also a good idea to set a model which contains all the properties required. I mean that maybe you have a useless property in a query, so the query model should exclude it.
I think I found the proper solution:
Create model class. Define the members with unknown depth and structure as JsonNode.
Then the model class could be used and the values of the JsonNode accessed using nice methods.
When having two classes that has the same name, but in different namespaces, ServiceStacks OrmLite is unable to distinguish between the two. For example:
Type type = typeof(FirstNameSpace.BaseModel);
using (IDbConnection db = _dbFactory.Open())
{
db.CreateTable(false, type); // Creates table "basemodel"
}
type = typeof(SecondNamespace.BaseModel);
using (IDbConnection db = _dbFactory.Open())
{
db.CreateTable(false, type); // Creates nothing as there already is a table 'basemodel', even though its a completely different object/class
}
Is there a general, clean way to make sure that this is resolved?
It is not ideal to be forced to name classes uniquely; a part of the namespaces in .NET is to group and categorize different classes. Also, there might be third-party assemblies with the same class names, that is not available to change for you.
Is there a way to handle this?
OrmLite uses the name of the Type for the table name so you can’t use 2 different Types with the same name.
You will need to either rename one of the Types to avoid the collision or use the [Alias(“UseTableName”)] attribute to tell one of the Types to use a different RDBMS Table name.
I need to perform a search on several entities with the same string then order the results.
I've heard/read a little about FOSElasticaBundle, would this bundle be able to do it? It seems (to me) to have almost to much features for this purpose and I'm not sure it could run on a shared server (hostgator).
The other solution I can think of at the moment is doing the search "manually" (by using join and union) but I'm wondering where should I put such a function: in an existing controller, a new one, a new bundle or somewhere else?
I'm worried as well that this manual solution could come to a cost, especially on some non-indexable fields.
You would do custom entity repositories. Check out the docs. Basically this extends the default FindAll, FindOneBy, etc.
You would have a function like so:
class MyEntityRepository extends Doctrine\ORM\EntityRepository {
public function findByCustomRule(){
//this is mapped to your entity (automatically adds the select)
$queryBuilder = $this->createQueryBuilder('someAlias');
$queryBuilder->orderBy('...');
//this is mapped to any entity
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
$queryBuilder->select('...');
//result
$result = $queryBuilder->getQuery()->getResult();
}
}
This class is defined in the doctrine mapping and lives inside the Entity folder.. Check the docs out and you should get a basic idea.
I'm refactoring a project using DDD, but am concerned about not making too many Entities their own Aggregate Root.
I have a Store, which has a list of ProductOptions and a list of Products. A ProductOption can be used by several Products. These entities seem to fit the Store aggregate pretty well.
Then I have an Order, which transiently uses a Product to build its OrderLines:
class Order {
// ...
public function addOrderLine(Product $product, $quantity) {
$orderLine = new OrderLine($product, $quantity);
$this->orderLines->add($orderLine);
}
}
class OrderLine {
// ...
public function __construct(Product $product, $quantity) {
$this->productName = $product->getName();
$this->basePrice = $product->getPrice();
$this->quantity = $quantity;
}
}
Looks like for now, DDD rules as respected. But I'd like to add a requirement, that might break the rules of the aggregate: the Store owner will sometimes need to check statistics about the Orders which included a particular Product.
That means that basically, we would need to keep a reference to the Product in the OrderLine, but this would never be used by any method inside the entity. We would only use this information for reporting purposes, when querying the database; thus it would not be possible to "break" anything inside the Store aggregate because of this internal reference:
class OrderLine {
// ...
public function __construct(Product $product, $quantity) {
$this->productName = $product->getName();
$this->basePrice = $product->getPrice();
$this->quantity = $quantity;
// store this information, but don't use it in any method
$this->product = $product;
}
}
Does this simple requirement dictates that Product becomes an aggregate root? That would also cascade to the ProductOption becoming an aggregate root, as Product has a reference to it, thus resulting in two aggregates which have no meaning outside a Store, and will not need any Repository; looks weird to me.
Any comment is welcome!
Even though it is for 'reporting only' there is still a business / domain meaning there. I think that your design is good. Although I would not handle the new requirement by storing OrderLine -> Product reference. I would do something similar to what you already doing with product name and price. You just need to store some sort of product identifier (SKU?) in the order line. This identifier/SKU can later be used in a query. SKU can be a combination of Store and Product natural keys:
class Sku {
private String _storeNumber;
private String _someProductIdUniqueWithinStore;
}
class OrderLine {
private Money _price;
private int _quantity;
private String _productName;
private Sku _productSku;
}
This way you don't violate any aggregate rules and the product and stores can be safely deleted without affecting existing or archived orders. And you can still have your 'Orders with ProductX from StoreY'.
Update: Regarding your concern about foreign key. In my opinion foreign key is just a mechanism that enforces long-living Domain relationships at the database level. Since you don't have a domain relationship you don't need the enforcement mechanism as well.
In this case you need the information for reporting which has nothing to do with the aggregate root.
So the most suitable place for it would be a service (could be a domain service if it is related to business or better to application service like querying service which query the required data and return them as DTOs customizable for presentation or consumer.
I suggest you create a statistics services which query the required data using read only repositories (or preferable Finders) which returns DTOs instead of corrupting the domain with query models.
Check this