Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play framework 2.1 and Ebean : @ManyToOne and @OneToMany, CRUD and cascade problems

I want to realize is that: when I delete the category ,all its related articles can be deleted and when I delete the article, it can also be deleted in it's related category.

I set the mapping relationship @ManyToOne and @OneToMany(cascade = CascadeType.ALL, mappedBy = " category") just as the code below, but when I was doing unit test , several problems occurs, it doesn't work. This is my code:

@Entity
public class Article extends Model {
    @Id
    public Long id;     

    @Constraints.Required       
    public String title;

    @Constraints.Required
    @Lob
    @Basic(fetch = FetchType.LAZY)
    public String content;

    public boolean published = false;

    @Formats.DateTime(pattern="yyyy-MM-dd")
    public Date publishDate;

    @ManyToMany(cascade = CascadeType.REMOVE)
    @Column(nullable = true)
    public List<Tag> tags = new ArrayList<Tag>();

    @ManyToOne
    @Column(nullable = true)
    public Category category;

    public static Finder<Long, Article> finder = new Finder<Long, Article>(Long.class, Article.class);

    public Article(String title, String content, Tag[] tags) {
        this.title = title;
        this.content = content;
        this.publishDate = new Date();
        this.category = null;
        if(tags != null)
            for(Tag t : tags)
                this.tags.add(t);
    }

    public static List<Article> all() {
        return finder.orderBy("publishDate desc").findList();
    }

    public static Article create(String title, String content, Tag[] tags) {
        Article article = new Article(title, content, tags);
        article.save();
        article.saveManyToManyAssociations("tags");
        return article;
    }

    public static void delete(Long id) {
        finder.ref(id).delete();
    }

    public static void setCategory(Article article, Category c) {
        if(article.category != null)
            Category.removeArticle(c, article);
        article.category = c;   
        Category.addArticle(c, article);
        article.update();
    }
}

And This is the Category class:

@Entity
public class Category extends Model {
    @Id
    public Long id; 

    @Required
    public String name;

    @OneToMany(mappedBy = "category", cascade = CascadeType.ALL)
    Set<Article> articles;

    public static Finder<Long, Category> finder = new Finder<Long, Category>(Long.class, Category.class);

    public Category(String name) {
        this.name = name;
    }

    public static List<Category> all() {
         return finder.all();
    }

    public static Category create(String name) {
        Category category = new Category(name);
        category.articles = new HashSet<Article>();
        category.save();
        return category;
    }

    public static String rename(Long id, String newName) {
        Category category = finder.ref(id);
        category.name = newName;
        category.update();
        return newName;
    }

    public static void delete(Long id) {
        Category c = finder.ref(id);
        c.delete(); 
    }

    public static void addArticle(Category c, Article article) {
        if(! c.articles.contains(article)) {
            article.category = c;
            c.articles.add(article);
            article.update();
        }
    }

    public static void removeArticle(Category c, Article article) {
        if(c.articles.contains(article)) {
            Article.delete(article.id);
            c.articles.remove(article);
        }
    }

    public static Map<String,String> options() {
        LinkedHashMap<String,String> options = new LinkedHashMap<String,String>();
        for(Category c: Category.finder.orderBy("name asc").findList()) {
            options.put(c.id.toString(), c.name);
        }
        return options;
    }
}

This is my test:

@Test
public void categoryTest() {
    Category c1 = Category.create("Play");
    Category c2 = Category.create("SSH");
    Category c3 = Category.create("Python");
    Category c4 = Category.create("web");

    String newName = Category.rename(c3.id, "Django");

    Category.delete(c2.id);

    List<Category> list = Category.all();
    assertEquals(3, list.size());

    Map<String, String> map = Category.options();


    Article a1 = Article.create("Hello", "Hello world, My Blog!", null);
    Article a2 = Article.create("My Blog", "It's build by play framework", null);
    Article a3 = Article.create("Play", "Install Play", null);

    Category.addArticle(c1, a1);
    Category.addArticle(c1, a2);
    Category.addArticle(c3, a3);

    Category.delete(c3.id);
    Category.removeArticle(c1, a1);

    assertEquals(2, list.size());
    assertEquals("Play", list.get(0).name);

    //assertEquals("Django", map.get("3"));
    assertEquals(1, Article.all().size());

    assertEquals(1, c1.articles.size());
    assertEquals(false, c1.articles.contains(a1));
}

Below assetion can't pass.

assertEquals(2, list.size()); 

That means category can' be deleted now, but

Category.delete(c2.id); 

works!

assertEquals(1, Article.all().size()); 

Above assetion can't pass. That means category can't delete it's related articles. What should I do to solve this problem?

like image 304
Hedgehog Avatar asked Nov 12 '22 09:11

Hedgehog


1 Answers

In above code there is only one assertion that do not pass. This is:

assertEquals(2, list.size()); 

Why it is happening?

Let's look at the following code:

List<Category> list = Category.all();
assertEquals(3, list.size());
Category.delete(c3.id);
assertEquals(2, list.size());

In first line we take all categories and there are three of them.
In third line we delete one of categories. This category is properly deleted but list of categories computed in first line has still three elements. This is because this list does not represent the current state of database. It still holds result computed in first line of above code.
To make second assertion work properly we have to add following line between line 3 and 4:

list = Category.all();

Above code will compute current list of categories and assign it to variable `list'.

like image 138
rtruszk Avatar answered Dec 28 '22 17:12

rtruszk