About Question enthuware.oce-jpad.v6.2.439 :

Moderator: admin

Post Reply
heaven

Re: About Question enthuware.oce-jpad.v6.2.439 :

Post by heaven »

Without @MapKey the implicit is @MapKeyColumn and @MapKeyColumn is used if the key is NOT part of the value. @MapKeyClass is used in combination with @MapKeyColumn (because there is no possibility to derive the type as there is no field representing the key). If @MapKey is nor specified, then it is understood that the key is NOT part of the value. But in question assignment it is stated that cardNumber IS part of the value.

Therefore I still believe @MapKeyClass is invalid for the mapping in question assignment, as @MapKey MUST be used and this negates usage of @MapKeyClass.

Guest

Re: About Question enthuware.oce-jpad.v6.2.439 :

Post by Guest »

If we don't specify the field to use as key in the map how can entity manager fill in the map for a given object reading from database (if we have more than one String attribure in related entity for example)?

Guest

Re: About Question enthuware.oce-jpad.v6.2.439 :

Post by Guest »

@OneToMany(targetEntity=CreditCard.class)
@MapKeyClass(String.class)
private Map creditCards;

so finally, this is correct or no?

Guest

Re: About Question enthuware.oce-jpad.v6.2.439 :

Post by Guest »

@OneToMany(targetEntity=CreditCard.class)
@MapKeyClass(String.class)
private Map creditCards;

I think this is not correct. You have to specify somehow that column used as key is "cardNumber", and on this answer we don't have that.

admin
Site Admin
Posts: 10036
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

Re: About Question enthuware.oce-jpad.v6.2.439 :

Post by admin »

The given answer is correct. There is no need to specify the field that is used as a key of the map because the persistent provider doesn't care about it. Consider the following code:

Code: Select all

    public Map<String, CreditCard> createCustomerCreditcardRelationships(String[] params){
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        
        try 
        {
            tx.begin();
            Customer i = new Customer();
            i.setName("John Doe");

                CreditCard cc1 = new CreditCard();
                cc1.setCardNumber("11111111111");
                cc1.setCardType(CreditCardType.VISA);

                CreditCard cc2 = new CreditCard();
                cc2.setCardNumber("22222222222");
                cc2.setCardType(CreditCardType.AMEX);

                CreditCard cc3 = new CreditCard();
                cc3.setCardNumber("33333333333");
                cc3.setCardType(CreditCardType.MASTERCARD);
                
                Map<String, CreditCard> ccList = new HashMap<String, CreditCard>();
                ccList.put(cc1.getCardNumber(), cc1); //you can put any string as the key.
                ccList.put(cc2.getCardNumber(), cc2);
                ccList.put(cc3.getCardNumber(), cc3);
                i.setCreditCards(ccList);
            em.persist(i);
            tx.commit();
            System.out.println("Customer and CCs stored.");
            return ccList;
        }
        finally 
        {
            //tx should have been committed at this point, 
            //if it is not something went wrong. So rollback.
            if (tx.isActive()) {
                tx.rollback();
            }

            em.close();
        }
    }

    public Map<String, CreditCard> testCustomerCreditcardRelationships(String[] params){
        EntityManager em = emf.createEntityManager();
        Integer custId = Integer.parseInt(params[0]);
        
        try 
        {
            Customer c = em.find(Customer.class, custId);
            System.out.println(" Got customer "+c);
            return c.getCreditCards(); //This will return the map and its keys will be whatever you stored earlier.
        }
        finally 
        {
            em.close();
        }
    }

The point to understand here is that even though it is desirable to specify @MapKey(name="cardNumber"), it is not required.
If you like our products and services, please help us by posting your review here.

admin
Site Admin
Posts: 10036
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

Re: About Question enthuware.oce-jpad.v6.2.439 :

Post by admin »

The following is the code for Customer.java

Code: Select all

@Entity
public class Customer {
    
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    @OneToMany(cascade = {CascadeType.ALL }, fetch= FetchType.EAGER)
    //@MapKey(name="cardNumber")  //It works fine with and without this line
    private Map<String, CreditCard> creditCards;
     
    //getters and setters for ID, name, and creditCards.

}
If you like our products and services, please help us by posting your review here.

Pan Niedxwiedx
Posts: 3
Joined: Tue Jul 02, 2013 1:14 pm
Contact:

Re: About Question enthuware.oce-jpad.v6.2.439 :

Post by Pan Niedxwiedx »

I agree with guys. Correctness of answer C is arguable. The question clearly stays that map key should be mapped to the same column that cardNumber field is. With answer C you will end up with two not related columns.

linwh0520
Posts: 1
Joined: Tue May 06, 2014 10:49 am
Contact:

Re: About Question enthuware.oce-jpad.v6.2.439 :

Post by linwh0520 »

I don't understand why (c) is correct. If you do not specify column name of map's key, how can entity manager know what value to load into map's key?
e.g.:

Code: Select all

Customer_Table:
Customer_ID  Customer_Name
1001                 A
1002                 B
Creditcard_Table:
CardID(int, PK)   CardNamber(String)  Issuer(String)   Customer_ID (FK)
9001                 1111222233334444   Citibank            1002
9002                 5555666677778888   Amex                1002
What are the key values of following "ccMap"?
Map<String, CreditCard> ccMap = em.load(1002, Customer.class).getCreditCards();

From one of previous post:
“There is no need to specify the field that is used as a key of the map because the persistent provider doesn't care about it.” and "//This will return the map and its keys will be whatever you stored earlier."--- They do not make sense.
What if
ccList.put(cc3.getCardNumber(), cc3);
is replaced by
ccList.put(cc3.getIssuer(), cc3);
?

As one of another previous post pointed out, (c) ends up with map's key being mapped to an extra column, not cardNumber column

admin
Site Admin
Posts: 10036
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

Re: About Question enthuware.oce-jpad.v6.2.439 :

Post by admin »

You are missing the point. The persistent provider doesn't automatically associate cardnumber with the card. The code does it. Please see the lines in the code that I gave above:

Code: Select all

                ccList.put(cc1.getCardNumber(), cc1); //you can put any string as the key.
                ccList.put(cc2.getCardNumber(), cc2);
                ccList.put(cc3.getCardNumber(), cc3);
                i.setCreditCards(ccList);
What if
ccList.put(cc3.getCardNumber(), cc3);
is replaced by
ccList.put(cc3.getIssuer(), cc3);
That is not persistence provider's problem. The PP does not manage the semantics of the contents of your map. It only manages the storage of the map. If you store wrong data, you will get back wrong data.

You might want to try out the code given above.

HTH,
Paul.
If you like our products and services, please help us by posting your review here.

Post Reply

Who is online

Users browsing this forum: No registered users and 24 guests