Как использовать аннотацию @MapKey с 2 уровнями? - PullRequest
3 голосов
/ 16 января 2011

этот вопрос похож на этот другой вопрос , который я задал, но немного отличается.

У меня есть это:

class A{

  private List<B> bs;

  ...
}

class B{

  private Long id;
  private C c;
  ...
} 

class C{

  private Long id;
  private String name;
  ...
} 

И яХотелось бы иметь это:

class A{

  // the map should have b.c.name as key
  private Map<String,B> bs;

  ...
}

class B{

  private Long id;
  private C c;
  private A a;
  ...
} 

class C{

  private Long id;
  private String name;
  ...
} 

Я не знаю, понятно ли, что я хотел бы сделать, но это так же просто, как сопоставить отношение один ко многим сКарта с именем C в качестве ключа карты и b в качестве значения.

Заранее спасибо, Neuquino

Ответы [ 3 ]

4 голосов
/ 20 января 2011

Короткий ответ: ты не можешь этого сделать.

Но вот решение, которое может подойти для вашей проблемы:

В объекте A все еще определено отношение к объекту B как List (или даже лучше как Set, так что один и тот же B не может содержаться более одного раза).

@OneToMany(mappedBy="a")
private Set<B> bs;

Поскольку вы не хотите показывать простой список, пропустите getter и setter для as.

Затем вы можете определить получатель для вашей карты, которая строит карту на лету:

// a transient field to cache the map
private transient Map<String, B> bsMappedByCName;

public Map<String, B> getBsMappedByCName() {
  if(bsMappedByCName == null) {
    bsMappedByCName = new HashMap<String, B>();
    for(B b : bs) {
      mapB(b);
    }
  }
  // return as unmodifiable map so that it is immutable for clients
  return Collections.unmodifiableMap(bsMappedByCName);
}

private void mapB(B b) {
  // we assume here that field c in class B and likely also field name in class C are not nullable. Further more both of this fields sould be immutable (i.e. have no setter).
  if(bsMappedByCName.put(b.getC().getName(), b) != null) {
    // multiple bs with same CName, this is an inconsistency you may handle 
  }      
}

Последний вопрос, который необходимо решить, - это как добавить новый B в A или удалить его. В соответствии со стратегией возврата карты как неизменяемой мы должны предоставить некоторые методы добавления и удаления в классе A:

public void addB(B b) {
  bs.add(b);
  mapB(b);
}

public void removeB(B b) {
  bs.remove(b);
  bsMappedByCName.remove(b.getC().getName());
}

Другой вариант - заменить return Collections.unmodifiableMap(...) на (вдохновленный ObservaleCollection от apache ):

return new Map<String, B>() {
  // implement all methods that add or remove elements in map with something like this
  public B put(String name, B b) {
    // check consistency
    if(!b.getC().getName().equals(name)) { 
      // this sould be handled as an error
    }
    B oldB = get(name);
    mapB(b);
    return oldB;
  }

  // implement all accessor methods like this
  public B get(String name) {
    return bsMappedByCName.get(name);
  }

  // and so on...
};
0 голосов
/ 25 января 2011

Если все три класса являются сущностями, вы можете попробовать изменить его на Map cs, поместить обратное поле в C из отношения B и изменить отношение B-A на C-A:


class A {
   // the map should have c.name as key
   @OneToMany
   private Map<String, C> cs;
   ...

   // This method is for getting the B for a key, like it was before.
   public B getB(String key) {
       return cs.get(key).getB();
   }
}

class B {

  private Long id;

  @OneToOne // Or perhaps @ManyToOne.
  private C c;
  ...
} 

class C {

  private Long id;
  private String name;

  @OneToOne(mappedBy="c") // Or perhaps maybe @OneToMany
  private B b;
  ...

  @ManyToOne(mappedby="cs")
  private A a;
} 

Я предполагаю, что три класса являются сущностями. Если C является Embeddable, поэтому я не знаю, что делать.

0 голосов
/ 21 января 2011

У меня есть решение для вашей награды. И это действительно работает для меня.

Этот игрушечный пример работает с небольшим предупреждением об устаревании @CollectionOfElements. Вы могли бы преодолеть это, заменив его более новой аннотацией, которая заменяет это.

package com.wladimir.hibernate;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;

import org.hibernate.annotations.CollectionOfElements;

@Entity
public class A {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    @CollectionOfElements
    @JoinTable
    private Map<String, B> bs = new HashMap<String, B>();

    public A() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Map<String, B> getBs() {
        return bs;
    }

    public void setBs(Map<String, B> bs) {
        this.bs = bs;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "A [bs=" + bs + ", id=" + id + ", name=" + name + "]";
    }

}




package com.wladimir.hibernate;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class B {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    @ManyToOne
    private C c;

    @ManyToOne
    private A a;

    public B() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public C getC() {
        return c;
    }

    public void setC(C c) {
        this.c = c;
    }

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "B [a=" + a.getName() + ", c=" + c.getName() + ", id=" + id
                + ", name=" + name + "]";
    }

}




package com.wladimir.hibernate;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class C {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    public C() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "C [id=" + id + ", name=" + name + "]";
    }
}


package examples.hibernate;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

public class PersistenceUtil {
    private static final SessionFactory sessionFactory;

    static {
        Log log = LogFactory.getLog(PersistenceUtil.class);

        try {
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (HibernateException ex) {
            // Make sure you log the exception, as it might be swallowed
            log.error("Initial SessionFactory creation failed.", ex);
            throw ex;
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

}



package examples.hibernate;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;

import com.wladimir.hibernate.A;
import com.wladimir.hibernate.B;
import com.wladimir.hibernate.C;

import java.util.List;

import examples.hibernate.domain.*;

public class Tester{
    private SessionFactory factory;

    public Tester(SessionFactory factory) {
        this.factory = factory;
    }

    @SuppressWarnings("unchecked")
    public void runABC(String operation) {
        Session session = factory.getCurrentSession(); // obtain/start unit of
        // work
        Transaction tx = null;
        try {
            tx = session.beginTransaction(); // start transaction

            if ("Create".equals(operation)) {
                A a = new A();
                a.setName("A " + System.nanoTime());

                C c = new C();
                c.setName("C " + System.nanoTime());
                session.save(c);


                B b = new B();
                b.setName("B " + System.nanoTime());

                b.setA(a);
                b.setC(c);

                a.getBs().put(b.getName(), b);

                session.save(b);

                B b2 = new B();
                b2.setName("B " + System.nanoTime());

                b.setA(a);
                b.setC(c);

                a.getBs().put(b.getName(), b);

                session.save(a);


            } else if ("Read".equals(operation)) {
                System.out.println("Reading data set.");
                List<A> as = (List<A>) session.createCriteria(A.class)
                        .addOrder(Order.asc("name")).list();
                for (A a : as) {
                    System.out.println(a);
                }
            }
            tx.commit(); // commit transaction & end unit of work

        } catch (RuntimeException ex) {
            if (tx != null)
                tx.rollback(); // abort transaction
            throw ex;
        }
    }


    // main application loop
    public static void main(String args[]) throws Exception {
        Tester app = new Tester(PersistenceUtil.getSessionFactory());

        String operation = null;
        if (args.length == 1) {
            operation = args[0];
        }

        app.runABC(operation);

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...