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.

  1. the type want map<country, map<state, collection<city>>>,
    not map<country, map<state, city>>.

  2. 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

Popular posts from this blog

aws api gateway - SerializationException in posting new Records via Dynamodb Proxy Service in API -

asp.net - Problems sending emails from forum -