持久化Map <entity,double =“”>:在连接表</entity,>中使用BLOB而不是String键

时间:2015-01-21 12:20:05

标签: java jpa derby

我正在开发卡路里计算器。我有实体Dish(由食材或其他菜肴组成的食物)和Ingredient(原子食用,例如“土豆”的“水”)。两者都扩展了实现接口AbstractEdible的类Edible

Dish包含recipe类型的字段Map<Edible, Double>,其中Double表示每个“菜元素”(成分或其他菜肴)的重量。

我正在尝试使用JPA和Derby来保留所有这些内容。我希望有一个包含以下字段的连接表:

  1. 菜实体的关键
  2. DOUBLE表示“菜单元素”重量的值
  3. “碟元素”实体的关键
  4. 这就是我现实中所拥有的:

    enter image description here

    而不是VARCHAR关键字“碟元素”实体我有一个BLOB而我无法找出原因。因此,我在更新现有的Dish时遇到问题(获得ERROR 42818: Comparisons between 'BLOB' and 'BLOB' are not supported)。我真的很乐意帮助你!

    package com.singularityfx.kcalibri2.model.edibles;
    
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    import javax.persistence.CollectionTable;
    import javax.persistence.Column;
    import javax.persistence.ElementCollection;
    import javax.persistence.Entity;
    import javax.persistence.MapKeyJoinColumn;
    import javax.persistence.OneToMany;
    import javax.persistence.Transient;
    import javax.persistence.JoinColumn;
    
    @Entity
    public class Dish extends AbstractEdible implements EdiblesCollection {
        @Transient
        private static final long serialVersionUID = -5646610412222252829L;
    
        @ElementCollection
        @CollectionTable(name="dish_recipe")
        @Column(name="weight")
        @MapKeyJoinColumn(name="ingredient_or_dish", referencedColumnName="name")
        private Map<Edible, Double> recipe = new HashMap<Edible, Double>();
    
        @Transient
        private KCalculator kCalculator = new KCalculator();
    
        public Dish() {}
    
        public Dish(String name, DishCategory category) {
            this.name = name;
            this.category = category;
        }
    
        @Override
        public double getKCalNonDessert() {
            kCalculator.init(recipe);
            return kCalculator.getkCalNonDessertPer100g();
        }
    
        @Override
        public double getKCalDessert() {
            kCalculator.init(recipe);
            return kCalculator.getkCalDessertPer100g();
        }
    
        @Override
        public double getKCal() {
            kCalculator.init(recipe);
            return kCalculator.getkCalPer100g();
        }
    
        @Override
        public double getKCalDessertTotal() {
            kCalculator.init(recipe);
            return kCalculator.getTotalKCalDessert();
        }
    
        @Override
        public double getKCalNonDessertTotal() {
            kCalculator.init(recipe);
            return kCalculator.getTotalKCalNonDessert();
        }
    
        @Override
        public double getKCalTotal() {
            kCalculator.init(recipe);
            return kCalculator.getTotalKCal();
        }
    
        public Double addIngredient(Edible edible, Double weight) {
            return recipe.put(edible, weight);
        }
    
        public Double removeIngredient(Edible edible) {
            return recipe.remove(edible);
        }
    
        @Override
        public Map<Edible, Double> getContent() {
            return recipe;
        }
    
        @Override
        public void setContent(Map<Edible, Double> content) {
            this.recipe = content;
        }
    
        @Override
        public void clearContent() {
            this.recipe.clear();
        }
    
        public double getWeight(Edible edible) {
            return recipe.get(edible);
        }
    
        public Collection<Edible> getEdibles() {
            return recipe.keySet();
        }
    
    }
    

    成分

    package com.singularityfx.kcalibri2.model.edibles;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.MappedSuperclass;
    import javax.persistence.NamedQuery;
    import javax.persistence.Transient;
    
    @Entity
    public class Ingredient extends AbstractEdible {
        @Transient
        private static final long serialVersionUID = -7669934586986624995L;
        private double kCal;
        private boolean isDessert;
    
        public Ingredient() {}
    
        public Ingredient(String name, IngredientCategory category, 
                double kCal, boolean isDessert) {
            this.name = name;
            this.kCal = kCal;
            this.category = category;
            this.isDessert = isDessert;
        }
    
        @Override
        public double getKCalNonDessert() {
            return isDessert ? 0 : kCal;
        }
    
        @Override
        public double getKCalDessert() {
            return isDessert ? kCal : 0;
        }
    }
    

    AbstractEdible

    package com.singularityfx.kcalibri2.model.edibles;
    
    import java.io.Serializable;
    
    import javax.persistence.CascadeType;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Inheritance;
    import javax.persistence.InheritanceType;
    import javax.persistence.JoinColumn;
    import javax.persistence.MappedSuperclass;
    import javax.persistence.OneToOne;
    
    @Entity
    @Inheritance(strategy=InheritanceType.JOINED)
    public abstract class AbstractEdible implements Edible, Serializable {
    
        private static final long serialVersionUID = 8684184950268663225L;
        @Id
        protected String name;
        @OneToOne()
        @JoinColumn(name="NAME_OF_CATEGORY")
        protected EdibleCategory category;
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public EdibleCategory getCategory() {
            return category;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setCategory(EdibleCategory category) {
            this.category = category;
        }
    
        @Override
        public String toString() {
            return name + " [" + category + "]";
        }
    
        @Override
        public int compareTo(Edible c) {
            return name.compareTo(c.getName());
        }
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result
                    + ((category == null) ? 0 : category.hashCode());
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            AbstractEdible other = (AbstractEdible) obj;
            if (category == null) {
                if (other.category != null)
                    return false;
            } else if (!category.equals(other.category))
                return false;
            if (name == null) {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            return true;
        }
    }
    

    食用

    package com.singularityfx.kcalibri2.model.edibles;
    
    import javax.persistence.Entity;
    import javax.persistence.Inheritance;
    import javax.persistence.InheritanceType;
    
    public interface Edible extends Comparable<Edible> {
        public double getKCalNonDessert();
        public double getKCalDessert();
        public String getName();
        public EdibleCategory getCategory();
    }
    

2 个答案:

答案 0 :(得分:1)

您的Edible界面扩展了Comparable。因此,您应该在Interface或Implementing类中覆盖equalshashCode。联接需要比较无法比较的对象,除非您覆盖equalshashCode

答案 1 :(得分:0)

我的错误在这里:

private Map<Edible, Double> recipe

Edible(由我的实体实现的接口)本身不是实体,因此持久性提供程序不会将地图密钥识别为实体。

当我引用抽象类(使用@Entity注释)而不是接口时,一切都按预期工作:

private Map<AbstractEdible, Double> recipe