【问题标题】:Converting JPA Entities to a Map将 JPA 实体转换为地图
【发布时间】:2015-07-18 19:31:24
【问题描述】:

总的来说,我对 JPA 和数据库还很陌生,我正在尝试自学一些这方面的知识。我想知道是否有可能将您检索到的特定实体的列表转换为地图。最终,我想获得所有单独实体的地图列表。

这是我得到的错误:

 java.lang.ClassCastException: consultant.billing.entity.WorkEntry cannot be   cast to java.util.Map

下面是我的实体和我尝试运行的代码:

@Entity
@Table(name = "work_entry")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "WorkEntry.findAll", query = "SELECT w FROM WorkEntry w"),
@NamedQuery(name = "WorkEntry.findByWorkEntryId", query = "SELECT w FROM WorkEntry w WHERE w.workEntryId = :workEntryId"),
@NamedQuery(name = "WorkEntry.findByDate", query = "SELECT w FROM WorkEntry w WHERE w.date = :date"),
@NamedQuery(name = "WorkEntry.findByHoursWorked", query = "SELECT w FROM WorkEntry w WHERE w.hoursWorked = :hoursWorked")})
public class WorkEntry implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "work_entry_id")
private Integer workEntryId;
@Column(name = "date")
@Temporal(TemporalType.DATE)
private Date date;
// @Max(value=?)  @Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
@Column(name = "hours_worked")
private Double hoursWorked;
@JoinColumn(name = "activity_id", referencedColumnName = "activity_id")
@ManyToOne
private Activity activityId;
@JoinColumn(name = "customer_id", referencedColumnName = "customer_id")
@ManyToOne
private Customer customerId;

public WorkEntry() {
}

public WorkEntry(Date date, Double hoursWorked, Customer customerId, Activity activityId) {
    this.date = date;
    this.hoursWorked = hoursWorked;
    this.activityId = activityId;
    this.customerId = customerId;
}


public WorkEntry(Integer workEntryId) {
    this.workEntryId = workEntryId;
}

public Integer getWorkEntryId() {
    return workEntryId;
}

public void setWorkEntryId(Integer workEntryId) {
    this.workEntryId = workEntryId;
}

public Date getDate() {
    return date;
}

public void setDate(Date date) {
    this.date = date;
}

public Double getHoursWorked() {
    return hoursWorked;
}

public void setHoursWorked(Double hoursWorked) {
    this.hoursWorked = hoursWorked;
}

public Activity getActivityId() {
    return activityId;
}

public void setActivityId(Activity activityId) {
    this.activityId = activityId;
}

public Customer getCustomerId() {
    return customerId;
}

public void setCustomerId(Customer customerId) {
    this.customerId = customerId;
}

@Override
public int hashCode() {
    int hash = 0;
    hash += (workEntryId != null ? workEntryId.hashCode() : 0);
    return hash;
}

@Override
public boolean equals(Object object) {
    // TODO: Warning - this method won't work in the case the id fields are not set
    if (!(object instanceof WorkEntry)) {
        return false;
    }
    WorkEntry other = (WorkEntry) object;
    if ((this.workEntryId == null && other.workEntryId != null) || (this.workEntryId != null && !this.workEntryId.equals(other.workEntryId))) {
        return false;
    }
    return true;
}

@Override
public String toString() {
    return "consultant.billing.entity.WorkEntry[ workEntryId=" + workEntryId + " ]";
}

}

@Entity
@Table(name = "customer")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "Customer.findAll", query = "SELECT c FROM Customer c"),
@NamedQuery(name = "Customer.findByCustomerId", query = "SELECT c FROM Customer c WHERE c.customerId = :customerId"),
@NamedQuery(name = "Customer.findByFirstName", query = "SELECT c FROM Customer c WHERE c.firstName = :firstName"),
@NamedQuery(name = "Customer.findByLastName", query = "SELECT c FROM Customer c WHERE c.lastName = :lastName"),
@NamedQuery(name = "Customer.findByStreetAddress", query = "SELECT c FROM Customer c WHERE c.streetAddress = :streetAddress"),
@NamedQuery(name = "Customer.findByCity", query = "SELECT c FROM Customer c WHERE c.city = :city"),
@NamedQuery(name = "Customer.findByState", query = "SELECT c FROM Customer c WHERE c.state = :state"),
@NamedQuery(name = "Customer.findByPostalCode", query = "SELECT c FROM Customer c WHERE c.postalCode = :postalCode"),
@NamedQuery(name = "Customer.findByPhoneNumber", query = "SELECT c FROM Customer c WHERE c.phoneNumber = :phoneNumber"),
@NamedQuery(name = "Customer.findByEmail", query = "SELECT c FROM Customer c WHERE c.email = :email")})
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "customer_id")
private Integer customerId;
@Size(max = 75)
@Column(name = "first_name")
private String firstName;
@Size(max = 75)
@Column(name = "last_name")
private String lastName;
@Size(max = 250)
@Column(name = "street_address")
private String streetAddress;
@Size(max = 50)
@Column(name = "city")
private String city;
@Size(max = 50)
@Column(name = "state")
private String state;
@Size(max = 45)
@Column(name = "postal_code")
private String postalCode;
@Size(max = 45)
@Column(name = "phone_number")
private String phoneNumber;
// @Pattern(regexp="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", message="Invalid email")//if the field contains email address consider using this annotation to enforce field validation
@Size(max = 250)
@Column(name = "email")
private String email;
@OneToMany(mappedBy = "customerId")
private Collection<ExpenseEntry> expenseEntryCollection;
@OneToMany(mappedBy = "customerId")
private Collection<WorkEntry> workEntryCollection;

我正在尝试运行的代码:

public Customer() {
}

String customerId = request.getParameter("customerId");
            Customer customer = customerServ.find(Integer.parseInt(customerId));
            request.setAttribute("customer", customer);

            String sDate = request.getParameter("sDate");
            Date parsedSDate = sdf.parse(sDate);
            java.sql.Date sqlSDate = new java.sql.Date(parsedSDate.getTime());

            String eDate = request.getParameter("eDate");
            Date parsedEDate = sdf.parse(eDate);
            java.sql.Date sqlEDate = new java.sql.Date(parsedEDate.getTime());

            List<Map> workDone = workServ.getWorkDoneByCustAndDate(Integer.parseInt(customerId), sqlSDate, sqlEDate);
            List<Map> expenses = expenseEntServ.getExpenseForCustIdAndDate(Integer.parseInt(customerId), sqlSDate, sqlEDate);

            List newInvoice = invoice.getInvoice(workDone,expenses);

我用来获取 WorkEntry 的方法:

public List<Map> getWorkDoneByCustAndDate(int custId, Date sDate, Date eDate) {
    String jpql = "SELECT w FROM WorkEntry w WHERE w.customerId.customerId = :customerId AND w.date BETWEEN :sDate AND :eDate";
    Query q = getEntityManager().createQuery(jpql);
    q.setParameter("customerId", custId);
    q.setParameter("sDate", sDate, TemporalType.DATE);
    q.setParameter("eDate", eDate, TemporalType.DATE);
    return q.getResultList();
}

【问题讨论】:

  • 错误是说该方法返回单个WorkEntry,但您正试图将其转换为List&lt;Map&gt; 这没有意义。
  • 我要返回多个条目。一个都没有
  • 请显示您对getWorkDoneByCustAndDate的方法定义
  • 编辑显示方法。
  • 它根据 javadcos docs.oracle.com/javaee/6/api/javax/persistence/…返回一个列表而不是一个地图

标签: java mysql jpa entity


【解决方案1】:

你可以这样做,但不能使用 JPA,在获得工作条目列表后,你可以使用 Java 反射或更简单,使用 BeanUtils 或 JACKSON 将任何 Java Bean(在你的情况下为 WorkEntry 类)转换为地图。

你可以看到这个 BeanUtils 库的例子来实现这个目标。

beanUtils example

您可以在获得列表后添加此代码:

List<Map> yourList=new ArrayList<Map>();
   List<WorkEntry> list=q.getResultList();
   for(WorkEntry we:list){
       BeanMap map=new BeanMap(we);
       yourList.add(map);
   }

希望对你有帮助。

【讨论】:

  • 这样行得通,我的下一个问题是每张地图都显示类似“activityId => advisor.billing.entity.Activity[activityId=200]”的内容,我怎样才能提取像“consultant”这样的值.billing.entity.Activity[activityId=200] 来自地图列表。我尝试执行 if 语句 where record.get("activityId").equals(),但这似乎不起作用
  • 你能分享你的代码吗?您是否尝试打印地图的每个值?我不确定我是否理解你想用你的地图列表做什么,但这是我的想法:
     for(Map mapOfWorkEntry:listOfMaps){ System.out.println("Map:"+mapOfWorkEntry); Activity act=(Activity)mapOfWorkEntry.get("activity"); System.out.println("Activity name:"+act.getActivityName()+"| Activity Id:"+act.getId()); Double hours=(Double)mapOfWorkEntry.get("hoursWorked"); System.out.println("Hours:"+hours); } 
  • 基本上我正在尝试这样做:'for (Map record : workDone) { if (record.get("activityId").equals(10)) { nonBillableHours += +Double.parseDouble (record.get("hoursWorked").toString());'
  • 好的,明白了,这行有错误:
    record.get("activityId").equals(10) record.get("activityId") 将返回一个对象(Activity.class 对象)并且您尝试与 10 值进行比较,因此最后您要比较引用,这种情况永远不会成立。要实现这一点,您需要:
    Activity activity=record.get("activityId");
    Integer id=activity.getId();//Im not sure if your activity class has this property.
    if(id==10){
    ` //do something&lt;br/&gt; }`
  • 另外,当您使用 JPA 访问嵌套对象的每个属性时,您将首先访问这个嵌套对象,在您的情况下,您希望访问内部的“activityId”你的Activity实体,这个Activity类是你的WorkEntry类的嵌套对象,你需要首先得到workEntry对象,然后是Activity对象,最后你可以从这个对象中得到“activityId”属性。请记住,如果您使用 @ManyToOne 将 activityId 映射为一个对象,那么您有一个嵌套对象,这就是您需要首先访问 Activity 类的原因。
【解决方案2】:

为时已晚,但这个例子非常实用,可以帮助你

ObjectMapper oMapper = new ObjectMapper();
List<Map> yourList=new ArrayList<Map>();
List<WorkEntry> list=q.getResultList();
for(WorkEntry we:list){
   yourList.add(oMapper.convertValue(we , Map.class);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 2019-04-22
    相关资源
    最近更新 更多