join - Joining entity objects by foreign key with Java Stream API -
i training using java steam api , implemented mentioned in title.
dissatisfied code.
for example, there 3 entity classes simple immutable bean.
code:
public class country { private final integer countryid; // pk, primary key private final string name; public country(integer countryid, string name) { this.countryid = countryid; this.name = name; } // omitting getters } public class state { private final integer stateid; // pk private final integer countryid; // fk, foreign key private final string name; public state(integer stateid, integer countryid, string name) { this.stateid = stateid; this.countryid = countryid; this.name = name; } // omitting getters } public class city { private final integer cityid; // pk private final integer stateid; // fk private final string name; public city(integer cityid, integer stateid, string name) { this.cityid = cityid; this.stateid = stateid; this.name = name; } // omitting getters }
these entities relation one many, not many many.
i want create map<country, map<state, city>>
object entity collections collection<country>
, collection<state>
, collection<city>
using pk , fk relations.
my implementation here.
code:
// entity collections set<country> countries = collections.singleton(new country(1, "america")); set<state> states = collections.singleton(new state(30, 1, "wasington")); set<city> cities = collections.singleton(new city(500, 30, "wasington, d.c.")); // intermediate maps map<integer, city> fkcitymap = cities.stream() .collect(collectors.tomap(city::getstateid, function.identity())); map<integer, state> fkstatemap = states.stream() .collect(collectors.tomap(state::getcountryid, function.identity())); map<integer, map<state, city>> fkstatecitymap = fkstatemap.entryset().stream() .collect(collectors.tomap(entry::getkey, entry -> collections.singletonmap( entry.getvalue(), fkcitymap.get(entry.getvalue().getstateid())))); // result map<country, map<state, city>> mapwhatiwant = countries.stream() .collect(collectors.tomap(function.identity(), country -> fkstatecitymap.get(country.getcountryid())));
it works, not elegant commented "intermediate maps" part, think.
there better way implement this?
update
there mistakes mentioned holger.
the type want
map<country, map<state, collection<city>>>
,
notmap<country, map<state, city>>
.i misunderstood washington , washington d.c.
so, code commented entity collections bad example.
the way, have defined intermediate maps, i.e. map<integer, city> fkcitymap
, mapping state id city, , map<integer, state> fkstatemap
, mapping country id state, establishing assumption there can 1 state
in country
, 1 city
in state
, indirectly allows 1 city
in entire country
.
of course, won’t notice long test data consist of 1 country
, 1 state
, 1 city
. worse, intended result type map<country, map<state, city>>
works if there 1 city
per state
. not implementation broken, task definition is.
let’s redefine result type map<country, map<state, set<city>>>
, allow more 1 city
per state
, can implement operation as
map<country, map<state, set<city>>> mapthatyouwant = countries.stream() .collect(collectors.tomap(function.identity(), c->states.stream() .filter(s -> objects.equals(s.getcountryid(), c.getcountryid())) .collect(collectors.tomap(function.identity(), s->cities.stream() .filter(city -> objects.equals(city.getstateid(), s.getstateid())) .collect(collectors.toset())))));
but note creating intermediate maps looking items might more efficient searching sets linearly multiple times. have care create right kind of maps.
map<integer,country> countrybyid = countries.stream() .collect(collectors.tomap(country::getcountryid, function.identity())); map<integer,set<city>> citiesbystateid = cities.stream() .collect(collectors.groupingby(city::getstateid, collectors.toset())); map<country, map<state, set<city>>> mapthatyouwant = states.stream() .collect(collectors.groupingby(s -> countrybyid.get(s.getcountryid()), collectors.tomap(function.identity(), s -> citiesbystateid.getordefault(s.getstateid(), collections.emptyset()))));
by way, washington, d.c. not in state washington.
Comments
Post a Comment