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

Moderator: admin

Post Reply
cosminvacaroiu

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

Post by cosminvacaroiu »

I don't understand why C is correct, because we want the key to be cardNumber field (String), and if we don't specify anything it defaults to the PK, which is cardId (Integer).

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

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

Post by admin »

cosminvacaroiu wrote:I don't understand why C is correct, because we want the key to be cardNumber field (String), and if we don't specify anything it defaults to the PK, which is cardId (Integer).
I don't think what you are saying is correct. You can use any value as the key of the map as long as it is of the type that is specified in @MapKeyClass.

Can you please tell me where you read that the key is the PK?

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

cosminvacaroiu

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

Post by cosminvacaroiu »

Well if you have 10 fields with the type String in the entity, how does it know which one do you want ?

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

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

Post by admin »

cosminvacaroiu wrote:Well if you have 10 fields with the type String in the entity, how does it know which one do you want ?
Why does it have to know? It will store whatever value you put as the key and retrieve it back. The value of the key is stored in a separate column.

When you use @MapKey, it becomes a special case where they key is the PK, but when you use @MakyKeyClass, you can use whatever value you want.
If you like our products and services, please help us by posting your review here.

Guest

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

Post by Guest »

Yeah, you're right thanks :D

Lenz

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

Post by Lenz »

The question states the you want the cardNumber field (String) of the CreditCard entity to be the key of the map.

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

would use a new field in the database (creditCards_KEY) which is wrong because it is not using the field.

The option:
@OneToMany(targetEntity=CreditCard.class)
@MapKeyClass(String.class)
@MapKey(name="cardNumber")
private Map<String, CreditCard> creditCards;

actually works and the @MapKeyClass annotation gets ignored

Piotr Sobczyk

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

Post by Piotr Sobczyk »

Yes, I have exactly the same opinion as Lenz.

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

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

Post by admin »

The question is talking about the value of the keys in the map not the name of column of the table used to store the key.

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

heaven

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

Post by heaven »

Hi,
since cardNumber is field of CreditCard, MapKey should be used. Then MapKeyClass should not be used as consequence (because persistence provider can determine the type from the field).

As stated in JPA spec:

Code: Select all

The MapKey annotation is used to specify the special case where the map key is itself the primary key or a persistent field or property of the entity that is the value of the map. The MapKeyClass annotation is not used when MapKey is specified.
Therefore in my opinion option C is not valid for the requested mapping. In this question I see only one valid answer - E.

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

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

Post by admin »

As per section 11.1.28, If the map is specified using Java generics, the MapKeyClass annotation and associated type need not be specified; otherwise they must be specified.

In this option (option c), Map is not generic. So it should be valid.

Further, the question does not impose any restriction (i.e. a foreign key constraint) on the columns of the tables used for mapping. So I think the given mapping will work. The only implication (or drawback of mapping it this way) is that the foreign key constraint will not be enforced.

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

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: 10043
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: 10043
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: 10043
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 13 guests