Hibernate: bad performance when removing element from many-to-many relation - performance

I have to Classes (UserSet and User) which have a many-to-many relation (i.e. every user can belong to some UserSets). In the database there is a UserSet Table, a User Table and an 'in between' Table (UsersToUserSets).
Now, if I want to remove a user from a UserSet by doing
userSet.getUsers().remove(user);
session.flush()
Hibernate first fetches all users belonging to userSet and then removes the one user and updates the 'inbetween' table.
As there may be thousands of users belonging to a UserSet this is very bad for the performance. Is there a way to avoid that all of the users are fetched?
The interesting parts of the mapping files look like this:
<class name="...UserSet">
...
<set name="users" table="T_UM_USERS2USER_SETS">
<key column="FK_USER_SET_ID" />
<many-to-many column="FK_USER_ID"
class="...User" />
</set>
...
</class>
<class name="...User">
...
<set name="userSets" table="T_UM_USERS2USER_SETS" inverse="true">
<key column="FK_USER_ID" />
<many-to-many column="FK_USER_SET_ID" class="...UserSet" />
</set>
</class>

All users for a particular UserSet are fetched because you're calling userSet.getUsers().remove(user). Performing any operation on a lazy collection causes collection to be fetched. What you can do is:
1) If userSets cardinality is lower than that of users (e.g. given user would only belong to few userSets) you can switch the inverse end of this relationship and invoke user.getUserSets().remove(userSet) - I'm assuming here you want to remove the association only and not the actual entity.
OR
2) You can define a named SQL query to delete the association row from T_UM_USERS2USER_SETS table and execute it.

Related

FetchXML attribute missing

When trying to retrieve an entity from Dynamics CRM using FetchXML one of the attributes appears to be missing.
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
<entity name="sb_eventbooking">
<attribute name="sb_name" />
<attribute name="sb_bookeridname" /> < problem here
<attribute name="createdon" />
<atrribute ........
There are 18 attributes in the FetchXML file but when running the application only 17 are available:
And sb_bookeridname is missing. If I go into the FetchXML file and enter an attribue that I know doesn't exist then I get an error:
'sb_eventbooking' entity doesn't contain attribute with Name = 'fakeattribute'.
So the application accepts there is an attribue called 'sb_bookeridname' but I cannot get a value from it. I know there can be issues with columns with null values but other attributes don't seem to have this problem. I do use this check on all attributes and get values for all the other attributes:
if (entity.Attributes.Contains("sb_bookeridname") && entity.GetAttributeValue<String>("sb_bookeridname") != null)
{
booking.bookeridname = entity.GetAttributeValue<String>("sb_bookeridname");
}
Edit 1:
I believe you have a lookup field with schema name: sb_bookerid. When we create a lookup field, CRM automatically creates a column in the table to store the text value corresponding to lookup. So when we create a lookup field sb_bookerid, then CRM will automatically create a column in the sb_eventbooking entity by the name sb_bookeridname.
This is the reason you do not receive an error on executing FetchXML query because a column with the name exists but CRM restricts from showing its value. So if you want to retrieve the value in sb_bookerid field, please use following -
if(entity.Contains("sb_bookerid"))
{
bookeridname=((EntityReference)entity.Attributes["sb_bookerid"]).Name
}
Hope it helps.
Here is cleaner way:
bookeridname = entity.GetAttributeValue<EntityReference>("sb_bookerid")?.Name;

SOLR dynamic fields and random filtering

I would like to perform a random sort of data coming from database using SOLR.
I found that SOLR has already a dynamicField that I can use with random field type :
<types>
...
<fieldType name="random" class="solr.RandomSortField" />
...
</types>
<fields>
...
<dynamicField name="random*" type="random" indexed="true" stored="false"/>
...
</fields>
But I don't understant how to fill the random* column. My data are issues from data import using SQL query.
Must I fill the column in db-data-config.xml and in which way ?
Thanks for any help.

Doctrine Criteria mixing up parameters in SQL query

Have a doctrine criteria that appears to be querying with mixed up parameters unless the association is first eagerly loaded.
The setup is quite simple. I have four entities: User, Business, UserBusiness, and UserBusinessMeta.
Each User can belong to one or more Businesses. Each UserBusiness can also have a list of Meta key/values for the given business. So,
User:
id: 3
Business:
id: 2
UserBusiness:
user_id: 3
business_id: 2
UserBusinessMeta (in the db there is also a unique constraint on user_id, business_id, key):
user_id: 3
business_id: 2
key: 'foo'
value: 'bar'
In my UserBusiness entity I have a method called: getFoo which has a criteria as shown below:
$criteria = Criteria::create()
->where(Criteria::expr()->eq('key', 'foo'))
->setMaxResults(1);
return $this->meta->matching($criteria)->first();
For some reason, when the SQL is created for this criteria, it reverses the business_id and user_id values when setting params so that it's looking for a business_id of 3 and a user_id of 2!
SELECT
t0.user_id AS user_id_1,
t0.business_id AS business_id_2,
t0.`key` AS key_3,
t0.`value` AS value_4,
t0.id AS id_5,
t0.user_id AS user_id_6,
t0.business_id AS business_id_7
FROM user_business_meta t0
WHERE (t0.`key` = ? AND t0.user_id = ? AND t0.business_id = ?) LIMIT 1
array (size=3)
0 => string 'foo' (length=11)
1 => int 2
2 => int 3
array (size=3)
0 => string 'string' (length=6)
1 => string 'integer' (length=7)
2 => string 'integer' (length=7)
However, if I set the UserBusinessMeta association fetch to be EAGER, then the variables are correctly loaded into memory and the above criteria -- not having to use SQL -- returns the right result.
I use XML mapping and there's really nothing special going on in them. The names of the columns and fields are correct as are the associations:
Business -> one-to-many UserBusiness
UserBusiness -> one to many UserBusinessMeta
The mapping for the association here is:
<one-to-many target-entity="UserBusinessMeta" mapped-by="UserBusiness" field="meta" orphan-removal="true">
<cascade>
<cascade-persist/>
<cascade-remove/>
</cascade>
</one-to-many>
And the user_id and business_id columns are mapped:
<id name="businessId" column="business_id" type="integer" />
<id name="userId" column="user_id" type="integer" />
In UserBusinessMeta the many-to-one association back to UserBusiness is defined as follows:
<many-to-one target-entity="UserBusiness" field="UserBusiness" inversed-by="meta">
<join-columns>
<join-column name="user_id" referenced-column-name="user_id" />
<join-column name="business_id" referenced-column-name="business_id" />
</join-columns>
</many-to-one>
Finally, the UserBusinessMeta entity also has the two columns for business_id and user_id mapped as so:
<field name="userId" column="user_id" type="integer" />
<field name="businessId" type="integer" column="business_id" />
It turns out the issue was due to having two ID's in the UserBusiness entity and one of them needing to be marked as an associate key. the following update fixed it:
<id name="business" column="business_id" type="integer" association-key="true" />

How to get data in ofbiz data model when just had partyID?

I'm using ofbiz framework and researching data modeling. But I'm confusing with getting data from an entity when just had partyID.
When I know a partyID, I can query at party table to get Party_type_id. Then, I use this Party_type_id to query at party_type to get type of party, example PERSON or PARTY_GROUP. But then how can I exactly go to PERSON or PARTY_GROUP to get individual information of them ? Because I don't show any relationship between party_type and name of table (PERSON or PARTY_GROUP).
I think viewEntity Can solve your problem.
Add the following view-entity in endityengine.xml.
<view-entity entity-name="PartyInfo"
package-name="org.ofbiz.party"
title="View that combines Person, Paryt and PartyGroup">
<member-entity entity-alias="P" entity-name="Party"/>
<member-entity entity-alias="PG" entity-name="PartyGroup"/>
<member-entity entity-alias="PER" entity-name="Person"/>
<alias entity-alias="P" name="partyId"/>
<alias entity-alias="PG" name="groupName"/>
<alias entity-alias="PER" name="firstName"/>
<alias entity-alias="PER" name="lastName"/>
<alias entity-alias="P" name="partyTypeId"/>
<view-link entity-alias="P" rel-entity-alias="PG" rel-optional="true">
<key-map field-name="partyId"/>
</view-link>
<view-link entity-alias="P" rel-entity-alias="PER" rel-optional="true">
<key-map field-name="partyId"/>
</view-link>
</view-entity>
which will have the party information including firstName,lastName Or GroupName (if PartyType = 'PARTY_GROUP') and PartyTypeId.
EntityCondition partyCondition = EntityCondition.makeCondition(UtilMisc.toList(
EntityCondition.makeCondition("partyId", EntityOperator.EQUALS, prtyId)), EntityOperator.AND);
List<GenericValue> partyDetails = delegator.findByCondition("PartyInfo", partyCondition, null, null);
Note : You cannot query databse using this table 'PartyInfo' ( Incase you are not aware of View entity)
Use the same party_id to query the table 'person' to get the info of the party of the party_type_id=PERSON
SELECT * FROM PERSON pers, PARTY p WHERE p.PARTY_ID=pers.PARTY_ID AND p.party_type_id='PERSON' AND pers.PARTY_ID='your-party-id'
Use the same party_id to query the table 'person' to get the info of the party of the party_type_id=PARTY_GROUP
SELECT * FROM PARTY_GROUP pg, PARTY p WHERE p.PARTY_ID=pg.PARTY_ID AND p.party_type_id='PARTY_GROUP' AND pg.PARTY_ID='your-party-id'
You may also try to navigate to Application>Framework>EntityEngine and check for the reln for any entity that you want. It gives quite a comprehensive info. Much like the foreign key connects.

Using a session variable in the where clause of a LINQ statement

Good afternoon all.
I have a page that displays data in a gridview based upon what the user selects for a material in a radiobutton list and how many they wish to see, a text box.
Upon logging into this page, a session variable for MemberID is created, MemberKey.
What I would like to do is pass this session variable into the LINQ statement so that only the specific member that has logged in sees their data:
ContextTypeName="VDSWeightsReportingService.CompleteWeightsDataContext" EnableInsert="True"
EnableUpdate="True" TableName="tblOnlineReportingCOMPLETEWEIGHTSFINALDEMOs"
Where="MaterialText == #MaterialText && Productpriority <= #Productpriority && MemberId == #MemberId">
<WhereParameters>
<asp:ControlParameter ControlID="radMaterial" Name="MaterialText"
PropertyName="SelectedValue" Type="String" />
<asp:ControlParameter ControlID="tbxHowMany" Name="Productpriority"
PropertyName="Text" Type="Int32" />
<asp:SessionParameter Name="MemberId" SessionField="MemberKey"
Type="String" />
</WhereParameters>
</asp:LinqDataSource>
I have tried to insert the session variable as above but without the LINQ no longer seems to go through the motions.
Can someone point out to me where I am going wrong?
If this doesn't work, or is not possible, can someone advise of a way around this? i.e. using this session variable in the LINQ where clause.
Make sure you select the correct session variable!!!!

Resources