You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by "M. Walter" <ma...@sbb.ch> on 2011/07/19 11:08:30 UTC

Best practice: Using fetch groups or a "simple" DTO?

I have a big entity with lots of data which I don't need to send to my
client. Only the primary key and a string should be delivered. All in all I
have to send 60000 entities. Now I have two possibilities:

1) I create a simple DTO with just the two required fields and fill it up
with JPA's constructor expression.
2) I use a fetch group which defines only the two required attributes on my
big entity. But all other attributes are initialized with default values I
guess and transported via the network as well.

What is best practice? What would you recommend? Maybe there are other
solutions?
Thanks for your input!

--
View this message in context: http://openjpa.208410.n2.nabble.com/Best-practice-Using-fetch-groups-or-a-simple-DTO-tp6598057p6598057.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by "M. Walter" <ma...@sbb.ch>.
Pinaki Poddar wrote:
> 
> You can switch on SQL logging by 
> <property name="openjpa.Log" value="SQL=TRACE"/>
> 
Unfortunately I can't because I'm using WepSphere Application Server V7. As
you probably know WebSphere simply ignores OpenJPA log properties. You have
to enable WebSphere tracing to see the OpenJPA logs in the trace.log file (
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.base.iseries.doc/info/iseries/ae/tejb_loggingwjpa.html
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.base.iseries.doc/info/iseries/ae/tejb_loggingwjpa.html
). This is really a pain and I don't know why IBM makes such nonsense. Maybe
just annoying software developers...

But I owe you the SQL log. Here it is:

SELECT t0.ID, t0.ROW_MUT_VERSION, t0.ROW_ERF_TSTAMP, t0.ROW_ERF_USER,
t0.ROW_MUT_TSTAMP, t0.ROW_MUT_USER, t0.ABKUERZUNG, t0.BEZEICHNUNG,
t0.BEZEICHNUNG_LANG, t0.BPUIC, t1.ID, t1.ROW_MUT_VERSION, t1.ROW_ERF_TSTAMP,
t1.ROW_ERF_USER, t1.ROW_MUT_TSTAMP, t1.ROW_MUT_USER, t1.CHECK_URL,
t1.FORMAT, t1.FTP_CLIENT_FACTORY, t1.INTERVALL, t1.NAME, t1.TYP,
t1.VERZEICHNIS_ARCHIV, t1.VERZEICHNIS_DB, t1.VERZEICHNIS_IN,
t0.FIKTIV_BP_TF, t0.GUELTIG_BIS, t0.GUELTIG_VON, t0.HALT_AUF_VERLANGEN_TF,
t2.ID, t2.ROW_MUT_VERSION, t2.ROW_ERF_TSTAMP, t2.ROW_ERF_USER,
t2.ROW_MUT_TSTAMP, t2.ROW_MUT_USER, t2.ABKUERZUNG, t2.ROW_GUELTIG_BIS,
t2.ROW_GUELTIG_VON, t3.ID, t3.ROW_MUT_VERSION, t3.ROW_ERF_TSTAMP,
t3.ROW_ERF_USER, t3.ROW_MUT_TSTAMP, t3.ROW_MUT_USER, t3.BESCHREIBUNG_DE,
t3.BESCHREIBUNG_EN, t3.BESCHREIBUNG_FR, t3.BESCHREIBUNG_IT,
t3.ROW_GUELTIG_BIS, t3.ROW_GUELTIG_VON, t3.TEXT_DE, t3.TEXT_EN, t3.TEXT_FR,
t3.TEXT_IT, t2.UIC_LAND, t2.WAEHRUNG, t2.ZEITZONE, t0.PRIO, t0.REGION,
t0.ROW_GUELTIG_BIS, t0.ROW_GUELTIG_VON, t0.UIC_BP, t0.UIC_KONTROLLZIFFER,
t0.X_GEO, t0.X_SWISS_GRID, t0.Y_GEO, t0.Y_SWISS_GRID, t0.Z_GEO,
t0.Z_SWISS_GRID
FROM BP t0, DATENQUELLE t1, LAND t2, TEXT_SD t3
WHERE t0.DATENQUELLE_ID = t1.ID(+) AND t0.LAND_ID = t2.ID(+) AND
t2.TEXT_SD_ID = t3.ID(+)

As you can see everything is selected although I'm using the fetch group.
There are joins to three other tables because some fields are eagerly
fetched. But I will set them to lazy. Maybe fetch plan does not work with
some relationships set to eager fetch type. I will create some JUnit tests
as you proposed but I don't know if this gets me further.

--
View this message in context: http://openjpa.208410.n2.nabble.com/Best-practice-Using-fetch-groups-or-a-simple-DTO-tp6598057p6625117.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by Pinaki Poddar <pp...@apache.org>.
> By the way this is the SELECT:
> [7/26/11 17:49:29:904 CEST] 0000000e Query         3   openjpa.Query:
> Trace: Executing query: SELECT b > FROM Bp b
This trace line is as OpenJPA sees the object query. If you look at the
corresponding SQL query that OpenJPA executes on the database, it will
supply more evidence on what is going wrong. You can switch on SQL logging
by 
  <property name="openjpa.Log" value="SQL=TRACE"/>


> OpenJPA's FetchPlan functionality I could select the fields I would like
> to load in a fine grained way. 
That is correct. I had also verified that the functional contract of fetch
plan has not regressed.

If you can supply a JUnit test with assertions, that will help further
analysis. 




-----
Pinaki Poddar
Chair, Apache OpenJPA Project
--
View this message in context: http://openjpa.208410.n2.nabble.com/Best-practice-Using-fetch-groups-or-a-simple-DTO-tp6598057p6622886.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by "M. Walter" <ma...@sbb.ch>.
Pinaki Poddar wrote:
> 
> How are you verifying whether a field data has been loaded in an entity
> instance or not?
> 
Well I have a breakpoint on line "final List<Bp> result =
ojpaQuery.getResultList();" where I can inspect the result list just after
the SELECT was executed.

By the way this is the SELECT:
[7/26/11 17:49:29:904 CEST] 0000000e Query         3   openjpa.Query: Trace:
Executing query: SELECT b FROM Bp b

I would have expected something like this using my fetch group: SELECT b.id,
b.bezeichnung FROM Bp b

Okay I have some relationships declared in Bp with fetch type EAGER so I
understand why OpenJPA is loading these fields with joins. But I thought
with OpenJPA's FetchPlan functionality I could select the fields I would
like to load in a fine grained way.

The method clearFetchGroups() did not solve my issue either. :-(

--
View this message in context: http://openjpa.208410.n2.nabble.com/Best-practice-Using-fetch-groups-or-a-simple-DTO-tp6598057p6622771.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by Pinaki Poddar <pp...@apache.org>.
Hi,
  How are you verifying whether a field data has been loaded in an entity
instance or not?
Please note that if you simply do
   myEntity.getSomeField();
within an active persistence context, then as a side-effect, the getter 
will fetch the field value from the database (you can see extra SQL being
issued if you turn on SQL tracing). This is a case of classic Schrodinger's
Observer Effect as related to JPA :)

   So to verify correctly, close the persistence context before accessing
the fields. 

   Also, instead of 
  ojpaQuery.getFetchPlan().removeFetchGroup(FetchGroup.NAME_DEFAULT); 
   do
   ojpaQuery.getFetchPlan().clearFetchGroups(); 

-----
Pinaki Poddar
Chair, Apache OpenJPA Project
--
View this message in context: http://openjpa.208410.n2.nabble.com/Best-practice-Using-fetch-groups-or-a-simple-DTO-tp6598057p6622661.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by Daryl Stultz <da...@opentempo.com>.
On Tue, Jul 26, 2011 at 6:02 AM, M. Walter <ma...@sbb.ch> wrote:

> I did the following:
>
> final OpenJPAQuery ojpaQuery =
> OpenJPAPersistence.cast(em.createNamedQuery(
> StammdatenQueryNames.FIND_ALL_BP.name()));
> ojpaQuery.getFetchPlan().removeFetchGroup(FetchGroup.NAME_DEFAULT);
> ojpaQuery.getFetchPlan().addFetchGroup("short");
> final List<Bp> result = ojpaQuery.getResultList();
>
> All fields and all relationships are loaded. Another idea?
>
> I've been following this thread and was inspired to try this myself to
improve a performance problem. I seem to be getting a similar outcome (no
effect). My query code looks like this:

System.out.println("**** 1");
final OpenJPAQuery ojpaQuery = OpenJPAPersistence.cast(query);
ojpaQuery.getFetchPlan().removeFetchGroup(FetchGroup.NAME_DEFAULT); // no
apparent effect
ojpaQuery.getFetchPlan().clearFetchGroups(); // try both ways
ojpaQuery.getFetchPlan().addFetchGroup("ScheduledAssignment.annotated");
salist.addAll(query.getResultList());
System.out.println("**** 2");
I'm getting a boatload of queries between the **** 1 and ****2. I'm
specifically trying to combat an N+1 problem, not sure this approach will
work. Anyway, my annotations on the root entity look like this:

@FetchGroups({
@FetchGroup(name = "ScheduledAssignment.annotated",
attributes = {
@FetchAttribute(name = "request"),
@FetchAttribute(name = "parentScheduledAssignment", recursionDepth = 0),
@FetchAttribute(name = "user"),
@FetchAttribute(name = "standInUser"),
@FetchAttribute(name = "role"),
@FetchAttribute(name = "manualEntry"),
@FetchAttribute(name = "brokenRuleLookup")
})
})

The SQL trace looks like this, I'm showing only the select for only the root
table:

SELECT t0.scheduledassignmentid,
t0.addedby, t0.caseid, t0.scatterautomationid, t0.modifiedby,
t0.rotationassignmentid,
t0.brokencustomruleexplanation, t0.addedon, t0.manualentry, t0.modifiedon,
 t0.timedebit

The first line is the PK, the second line FKs, the third basic. There are
more FKs and more basic props. I can't see any pattern to this. After some
back and forth, the select never changes (from t0, I didn't analyze the
others). In fact I reverted to my code prior to using the FetchGroup and
it's no different. I've made all my FKs lazy to no effect. I can't even say
that it appears the default fetch group is still active. What's being
selected doesn't even seem to match that.

I'm using OpenJPA 1.2.2

-- 
Daryl Stultz
_____________________________________
6 Degrees Software and Consulting, Inc.
http://www.6degrees.com
http://www.opentempo.com
mailto:daryl.stultz@opentempo.com

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by "M. Walter" <ma...@sbb.ch>.
Rick Curtis wrote:
> 
> Try removing the default fetchgroup?
> 

Hi Rick, thank you for your input!

I did the following:

final OpenJPAQuery ojpaQuery =
OpenJPAPersistence.cast(em.createNamedQuery(StammdatenQueryNames.FIND_ALL_BP.name()));
ojpaQuery.getFetchPlan().removeFetchGroup(FetchGroup.NAME_DEFAULT);
ojpaQuery.getFetchPlan().addFetchGroup("short");
final List<Bp> result = ojpaQuery.getResultList();

All fields and all relationships are loaded. Another idea?

--
View this message in context: http://openjpa.208410.n2.nabble.com/Best-practice-Using-fetch-groups-or-a-simple-DTO-tp6598057p6621633.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by Rick Curtis <cu...@gmail.com>.
Try removing the default fetchgroup?

Thanks,
Rick

On Mon, Jul 25, 2011 at 4:49 AM, M. Walter <ma...@sbb.ch> wrote:

> It does not work as described in the documentation. Or am I missing
> something?
>
> Here is my entity:
> @Entity
> @Table(name = "BP")
> @FetchGroup(name = "short", attributes = { @FetchAttribute(name = "id"),
> @FetchAttribute(name = "bezeichnung") })
> public class Bp extends BaseEntity implements Serializable {
>
>    public static final long serialVersionUID = -8334035710155503058L;
>
>    @Id
>    @SequenceGenerator(name = "SeqBp", sequenceName = "SEQ_BP")
>    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SeqBp")
>    @Column(name = "ID")
>    private Long id;
>    @Column(name = "ABKUERZUNG")
>    private String abkuerzung;
>    @Column(name = "REGION")
>    private String region;
>    @Column(name = "BEZEICHNUNG")
>    private String bezeichnung;
>    // lots of other fields and relations here
> }
>
> The code to load the entities with the named FetchGroup "short":
>
> final OpenJPAQuery ojpaQuery =
> OpenJPAPersistence.cast(em.createNamedQuery(
> StammdatenQueryNames.FIND_ALL_BP.name()));
> ojpaQuery.getFetchPlan().addFetchGroup("short");
> final List<Bp> result = ojpaQuery.getResultList();
>
> In the list I get the entities are loaded completely containing all fields
> and relations. Why?
>
> --
>
-- 
*Rick Curtis*

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by "M. Walter" <ma...@sbb.ch>.
It does not work as described in the documentation. Or am I missing
something?

Here is my entity:
@Entity
@Table(name = "BP")
@FetchGroup(name = "short", attributes = { @FetchAttribute(name = "id"),
@FetchAttribute(name = "bezeichnung") })
public class Bp extends BaseEntity implements Serializable {

    public static final long serialVersionUID = -8334035710155503058L;

    @Id
    @SequenceGenerator(name = "SeqBp", sequenceName = "SEQ_BP")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SeqBp")
    @Column(name = "ID")
    private Long id;
    @Column(name = "ABKUERZUNG")
    private String abkuerzung;
    @Column(name = "REGION")
    private String region;
    @Column(name = "BEZEICHNUNG")
    private String bezeichnung;
    // lots of other fields and relations here
}

The code to load the entities with the named FetchGroup "short":

final OpenJPAQuery ojpaQuery =
OpenJPAPersistence.cast(em.createNamedQuery(StammdatenQueryNames.FIND_ALL_BP.name()));
ojpaQuery.getFetchPlan().addFetchGroup("short");
final List<Bp> result = ojpaQuery.getResultList();

In the list I get the entities are loaded completely containing all fields
and relations. Why?

--
View this message in context: http://openjpa.208410.n2.nabble.com/Best-practice-Using-fetch-groups-or-a-simple-DTO-tp6598057p6617686.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by Pinaki Poddar <pp...@apache.org>.
Hi Walter,
  > The OpenJPA documentation is very spare about it

We are sorry to hear that FetchPlan documentation did not give you a good
picture of their capability. It is unfortunate because it is a powerful
feature of our runtime. 

> Do you have a detailed example? 
We have a large number of tests in this area but I am afraid that we do not
do a good job in explaining it via accessible examples. If you have access
to OpenJPA source code then look for Test*Fetch*.java and you will see lots
of complex tests.

> There is no way to dynamically create a new FetchPlan at runtime?
No. There is.
  EntityManager em = ...;
  FetchPlan plan = OpenJPAPersistence.cast(em).pushFetchPlan();

> I have to declare FetchGroup by annotations first in order to use the
> FetchPlan feature?
You can declare named groups in annotations. But you can as well create them
programmatically at runtime. Once you create a new one at runtime, then the
API methods listed in the manual, helps you to customize which fields you
want to access in that plan.

> what exactly do I get? My entity with the two fields only? My entity with
> two fields filled and the remains initialized to default values?  
You get your entity with two fields loaded. The other fields are *not*
loaded. If you access those other fields within a transaction, OpenJPA will
go and fetch them from database. If you access them in a remte process, then
they will normally return default values, but you can prohibit access to any
unloaded fields via configuration.   

> Are they initialized with "null" if they are not defined in my custom
> FetchGroup? 
See above.
http://openjpa.apache.org/builds/apache-openjpa-1.2.3-SNAPSHOT/docs/javadoc/org/apache/openjpa/persistence/OpenJPAEntityManager.html#pushFetchPlan()


[1]
http://openjpa.apache.org/builds/latest/docs/manual/manual.html#ref_guide_fetch

-----
Pinaki Poddar
Chair, Apache OpenJPA Project
--
View this message in context: http://openjpa.208410.n2.nabble.com/Best-practice-Using-fetch-groups-or-a-simple-DTO-tp6598057p6603239.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by "M. Walter" <ma...@sbb.ch>.
Pinaki Poddar wrote:
> 
> FetchPlan
> 
Great! But now how does it work? Do you have a detailed example? The OpenJPA
documentation is very spare about it (Chapter 5.7 of the reference guide
just lists the interface's methods - there are no hints about the results
and the Magazine entity is not complete).

My questions:
1) There is no way to dynamically create a new FetchPlan at runtime? I have
to declare FetchGroup by annotations first in order to use the FetchPlan
feature?
2) When I have an entity with 15 fields and I would like to load only two of
them (no relations), I have to create a FetchGroup accordingly. In the next
step I execute OpenJPAPersistence.cast(...), add my FetchGroup and then what
exactly do I get? My entity with the two fields only? My entity with two
fields filled and the remains initialized to default values?
3) What will be the result if the entity has some relations? Are they
initialized with "null" if they are not defined in my custom FetchGroup?

I'm using OpenJPA 1.2.3 so please keep that in mind when answering. Thank
you!

--
View this message in context: http://openjpa.208410.n2.nabble.com/Best-practice-Using-fetch-groups-or-a-simple-DTO-tp6598057p6601589.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.

Re: Best practice: Using fetch groups or a "simple" DTO?

Posted by Pinaki Poddar <pp...@apache.org>.
Hi Walter,
> What is best practice? 
FetchPlan

-----
Pinaki Poddar
Chair, Apache OpenJPA Project
--
View this message in context: http://openjpa.208410.n2.nabble.com/Best-practice-Using-fetch-groups-or-a-simple-DTO-tp6598057p6599040.html
Sent from the OpenJPA Users mailing list archive at Nabble.com.