I need (for a real good reason, trust me) to load what's almost the entire graph of my database using NHibernate. There are not so many entities, but the graph is kind of convoluted.
My graph looks something like :
EntityA
|
--> EntityB
|
--> List
|
--> EntityD
|
--> List
|
--> EntityF
Well... You get the idea.
I would like to load all of it with as few queries and roundtrips as possible, and possibly no select N+1 at all. Also I want to keep it as a graph, so I can easily loop through it later.
What's my best option? NHibernateUtil.Initialize()? Fetch()/FetchMany()? Future/MultiQuery?
I'm kind of lost, but I guess I'll have to do it in multiple operations. But what would the most efficient?
And bonus : all the entities have a IsPublished property. I want to be able to load either all the entities or only those that are published.
EDIT
In the end I tried this :
var applicationFields = NHibernateSession.Current.Query<ApplicationField>().Where(af => af.Ispublished)
.FetchMany(af => af.Illustrations)
.ThenFetch(i => i.InteractiveConfiguration)
.ThenFetchMany(ic => ic.UniqueSellingPoints)
.ThenFetchMany(usp => usp.Pictures)
.ToList();
Considering the way my graph looks, I think it's quite OK. Also I don't have multiple collections on same level, which is what induce cartesian products as far as I know.
For those who asked, it's not a recursion problem. Otherwise I would be using SQL Server CTE. Also I'm not updating any entity; it's just plain read (for an offline app).
But I'm clueless for my "bonus" question. I know EF can load partial collections based on filters, but it doesn't seem possible with NH.
short answer: a combination of Fetch()/FetchMany() and Future() depending on the usecase and expected list-sizes
Related
I'm managing a company website, where we have to display our products. We however do not want to handle the admin edit for this CPT, nor offer the ability to access to the form. But we have to read some product data form the admin edit page. All has to be created or updated via our CRM platform automatically.
For this matter, I already setup a CPT (wprc_pr) and registered 6 custom hierarchical terms: 1 generic for the types (wprc_pr_type) and 5 targeting each types available: wprc_pr_rb, wprc_pr_sp, wprc_pr_pe, wprc_pr_ce and wprc_pr_pr. All those taxonomies are required for filtering purposes (was the old way of working, maybe not the best, opened to suggestions here). We happen to come out with archive pages links looking like site.tld/generic/specific-parent/specific-child/ which is what is desired here.
I have a internal tool, nodeJS based, to batch create products from our CRM. The job is simple: get all products not yet pushed to the website, format a new post, push it to the WP REST API, wait for response, updated CRM data in consequence, and proceed to next product. Handle about 1600 products today on trialn each gone fine
The issue for now is that in order for me to put the correct terms to the new post, I have to compute for each product the generic type and specific type children.
I handled that by creating 6 files, one for each taxonomy. Each file is basically a giant JS object with the id from the CRM as a key, and the term id as a value. My script handles the category assertion like that:
wp_taxonomy = [jsTaxonomyMapper[crm_id1][crm_id2]] // or [] if not found
I have to say it is working pretty well, and that I could stop here. But I will have to take that computing to the wp_after_insert_post hook, in order to reaffect the post to the desired category on updated if something changed on the CRM.
Not quite difficult, but if I happen to add category on the CRM, I'll have to manually edit my mappers to add the new terms, and believe me that's a hassle.
Not waiting for a full solution here, but a way to work the thing. Maybe a way to computed those mappers and store their values in the options table maybe, or have a mapper class, I don't know at all.
Additional information:
Data from the CRM comes as integers (ids corresponding to a label) and the mappers today consist of 6 arrays (nested or not), about 600 total entries.
If you have something for me, or even suggestions to simplify the process, I'll go with it.
Thanks.
EDIT :
Went with another approach, see comment below.
I am looking to create a feature whereby a User can download any available documents related to the item from a tab on the PDP.
So far I have created a custom record called Documentation (customrecord_documentation) containing the following fields:
Related item : custrecord_documentation_related_item
Type : custrecord_documentation_type
Document : custrecord_documentation_document
Description : custrecord_documentation_description
Related Item ID : custrecord_documentation_related_item_id
The functionality works fine on the backend of NetSuite where I can assign documents to an Inventory item. The stumbling block is trying to fetch the data to the front end of the SCA webstore.
Any help on the above would be much appreciated.
I've come at this a number of ways.
One way is to create a Suitelet that returns JSON of the document names and urls. The urls can be the real Netsuite urls or they can be the urls of your suitelet where you set up the suitelet to return the doc when accessed with action=doc&id=_docid_ query params.
Add a target <div id="relatedDocs"></div> to the item_details.tpl
In your ItemDetailsView's init_Plugins add
$.getJSON('app/site/hosting/scriptlet.nl...?action=availabledoc').
then(function(data){
var asHtml = format(data); //however you like
$("#relatedDocs").html(asHtml);
});
You can also go the whole module route. If you created a third party module DocsView then you would add DocsView as a child view to ItemDetailsView.
That's a little more involved so try the option above first to see if it fits your needs. The nice thing is you can just about ignore Backbone with this approach. You can make this a little more portable by using a service.ss instead of the suitelet. You can create your own ssp app for the function so you don't have to deal with SCAs url structure.
It's been a while, but you should be able to access the JSON data from within the related Backbone View class. From there, within the return context, output the value you're wanting to the PDP. Hopefully you're extending the original class and not overwriting / altering the core code :P.
The model associated with the PDP should hold all the JSON data you're looking for. Model.get('...') sort of syntax.
I'd recommend against Suitelets for this, as that's extra execution time, and is a bit slower.
I'm sure you know, but you need to set the documents to be available as public as well.
Hope this helps, thanks.
I am working on a CakePHP3 application that will be used to display information about which products our suppliers are currently offering.
** Different Vendors provide their product lists in different ways, CSV, JSON, or by way of a web scrape **
I have 2 models that I have created:
Vendors - This references a specific Vendor that we use.
VendorProducts - This references all the products that all of our vendors offer.
I would like to be able to call something like:
$vendor->getAvailableProducts()
and have it either get the CSV and parse it, grab the JSON, or scrape the suppliers website and use this to populate the VendorProducts table in the database with products from this supplier.
I understand the idea behind Fat Models and Skinny Controllers, however I'm having a bit of difficulty implementing this feature.
I would like to provide the following functionality.
The Vendor's getAvailableProducts() function can be called via the web interface AND/OR a cakephp shell script that could be run in a cron job.
As some functionality (like scraping the website) takes a considerable amount of time, I would like to be able to see the progress of this function in the view,
eg: X/Y Products Updated from {Supplier}.
This can be broken down into the following questions:
1. Which file should my "getAvailableProducts()" function go in?
2. As each $vendor has a unique updateProducts() function, how would the correct function be called from $vendor->getAvailableProducts()
// something like this?
public function getAvailableProducts() {
if($vendor->name == "SupplierA") {
getProductsFromSupplierA();
}
if($vendor->name == "SupplierB") {
getProductsFromSupplierB();
}
..., etc.
}
3. How can the progress of this function be returned to a View?
Don't use table classes for that create a new namespace within the model layer or in the app itself:
src/Vendor
src/Model/Vendor
Have a factory that constructs and returns you the Vendor classes:
$vendorA = VendorFactory::get('SupplierA');
$vendorB = VendorFactory::get('SupplierB');
Each vendor class must implement a method fetchProducts(), use an interface or an abstract base class for that.
The method should return a normalized array that can be used to turn the products in entities:
$this->newEntities(VendorFactory::get('SupplierA')->fetchProducts());
You'll have a hard time determining the progress if there is no way to know the total amount of records. Which is likely when you scrape the website. Same issue applies when the API doesn't tell you the total amount of records per JSON data set. If you're able to get that total count somehow you can do this:
$this->newEntities(VendorFactory::get('SupplierA')->fetchProducts([
'limit' => 50,
'offset' => 0
]);
And implement pagination for the vendor which you can then use to run over all the records in a while() loop in chunks of X records. If you trigger that via shell you can create a "job" for that and update the progress after each chunk. There are multiple existing solutions for this kind of task already out there. Finally use Comet or Websockets to get the status updated on your website. Or the old way: Trigger an AJAX request every X seconds to check the status.
There is a lot more that could be said, but this is actually already a very broad question, there is very likely not enough detail to cover all cases. Also it might be possible (I'm pretty sure) there are different ways to solve this.
I'm creating some custom queries and need to figure out the relation between Member Groups and Document Groups.
My ultimate goal is to display the resources belonging to a particular User Group when a user log in. I am able to get their User ID from Sessions and so the relations I have figured out so far are:
User ID -> Member Groups Table -> ??Unknown table that pairs Member Groups with Document Groups?? -> Document Groups Table- > Resources Table
I just cant find that missing table(s)!
If any one can help me out that would be awesome!
Thanks
(ps: using Revo)
EDIT: added image for assitance
You could use some of the built-in MODX methods to achieve this.
This is not tested and might not work, but this might be a way to do it:
// userGroups = membergroups
$userGroups = $user->getUserGroups();
foreach ($userGroups as $userGroup) {
$resGroups = $userGroup->getResourceGroups();
foreach ($resGroups as $resGroup) {
$resources = $resGroup->getResources();
// merge resources into an array or something
}
}
Check out moduser.class.php, modusergroup.class.php, and modresourcegroup.class.php to see the queries behind these methods. You might be able to adapt them to one more efficient query.
Also, if I haven't misunderstood what you want to achieve then your results should be similar to what a user would see in the resource tree in the manager when logged in?
That uses the resource/getnodes.class.php processor, which retrieves all possible resources for each context using getCollection, then loops through each and decides whether to display or not by using $resource->checkPolicy('list'). That might be another approach to consider.
I usually work with custom data rather than MODX resources so would be keen to hear how you get on with this.
I know this is really, really old, but I came across this question looking for the answer myself. After a bit more digging I've found that it's the access_resource_groups table that links document_groups and member_groups
document_groups.id = access_resource_groups.target
member_groups.id = access_resource_groups.principal
For example I have a wpf window bound to an customer Entity (let suppose it's cus1). Then I load another entity from context :
customer cus2 = context.customers.where(x=>x.id=10).FirstOrDefault();
Now I want cus1 = cus2 ? I can do this way :
cus1.name = cus2.name;
cus1.address = cus2.address;
...
...
This way meets my case (the content of textboxs in the form change immediately into values of cus2) but I wonder if there is anyway to make it shorter since cus1=cus2 doesn't work ?
Thanks
You can use the memberwise Clone method to make a shallowcopy of a business object:
See http://msdn.microsoft.com/de-de/library/system.object.memberwiseclone.aspx
You could also use Serialization or Reflection, to do it on your own. However both oof the methods are slower then writing it directly.
Take a look at this article. Maybe you will find it helpful:
http://www.codeproject.com/KB/dotnet/CloningLINQ2Entities.aspx
Edit:
Btw. Remember, using using MemberwiseClone, in case of ReferenceTypes will effect in copying the references, not objects.
If you want to update the values of a Customer entity in memory with the newest values in the datastore you can use the Refresh method on your ObjectContext.
Here is the documentation.
In your case it would look like:
context.Refresh(RefreshMode.StoreWins, cus1);
If you really want to map two entities you could have a look at AutoMapper. AutoMapper will help you by automatically mapping entities to each other with a default setup that you can tweak to your needs.