【问题标题】:Ebean filter findList result with other tableEbean过滤findList结果与其他表
【发布时间】:2012-11-24 13:06:57
【问题描述】:

在检索对象列表时,我想根据另一个我只有 ID 的表过滤结果。对象在 ORM 模型中没有链接,而是只包含一个 UUID。

即:

@Entity
class A {
    @Id
    private UUID id;
    private UUID refB; // links to B
}

@Entity
class B {
    @Id
    private UUID id;
    private boolean visible;
}

我想检索 B.hidden 为假或 B 不存在的所有 A。

在 SQL 中我会做类似的事情

SELECT t0.* FROM a_table t0 LEFT JOIN b_table t1 ON (t0.ref_b = t1.id)
    WHERE t1.hidden IS NULL OR t1.hidden = 0;

我不只是使用 RawSql 的原因是我找不到在选择中使用通配符的任何方法,因此必须在选择中维护和手动添加所有属性。

我也试过

List<A> listA = Ebean.find(A.class).where()
     .join("LEFT JOIN b_table t1 ON (t0.ref_b = t1.id)")
     .where().in("t1.hidden", "0", "NULL");

然后我得到一个错误,因为 WHERE 放在“LEFT JOIN”之前。

我认为“正确”的方法是将“private UUID refB”替换为“private B refB”。但这样做会更容易绕过某些安全措施。

这可能吗,还是我必须在 RawSql 中添加所有属性?

【问题讨论】:

    标签: join filter ebean


    【解决方案1】:

    Ebean 中的过滤不仅仅是为了操作WHERE 子句,请查看other question 中的比较。

    这里有一个正确的方法(我更改了模型以显示完整的工作示例)

    型号

    @Entity
    public class A extends Model {
    
        @Id
        public Integer id;
    
        @ManyToOne
        public B b;
    
        public static Finder<Integer, A> find
                    = new Finder<Integer, A>(Integer.class, A.class);
    
    }
    
    @Entity
    public class B extends Model {
    
        @Id
        public Integer id;
        public Boolean hidden;
    
        public static Finder<Integer, B> find
                = new Finder<Integer, B>(Integer.class, B.class);
    
    }
    

    控制器

    public static Result index() {
    
        // Insert some data one every request
        B bFalse = new B();
        bFalse.hidden = false;
        bFalse.save();
    
        B bTrue = new B();
        bTrue.hidden = true;
        bTrue.save();
    
        A a1 = new A();
        a1.b = bFalse;
        a1.save();
    
        A a2 = new A();
        a2.b = bTrue;
        a2.save();
    
        A a3 = new A();
        a3.b = bTrue;
        a3.save();
    
        // Let's search...
        List<A> aListOfNotHidden = A.find.where().and(Expr.eq("b.hidden", false), Expr.isNotNull("b.hidden")).findList();
        for (A a : aListOfNotHidden) {
            Logger.info("NOT hidden " + a.id);
        }
    
        List<A> aListOfHidden = A.find.where().eq("b.hidden", true).findList();
        for (A a : aListOfHidden) {
            Logger.warn("HIDDEN " + a.id);
        }
    
        return ok("check logs in your console");
    }
    

    H2的结果SQL

    -- all NOT hidden
    select t0.id c0, t0.b_id c1
    from a t0
    left outer join b t1 on t1.id = t0.b_id
    where (t1.hidden = false  and t1.hidden is not null ) 
    
    -- all hiden
    select t0.id c0, t0.b_id c1 
    from a t0
    left outer join b t1 on t1.id = t0.b_id  
    where t1.hidden = true 
    

    或者,您也可以使用 SqlQuery 仅获取 SqlRows(不是对象)检查链接的 API 以获取使用示例、设置命名参数等:

    List<SqlRow> rows = Ebean.createSqlQuery("select t0.*  " +
            "from a t0 left outer join b t1 on t1.id = t0.b_id " +
            "where (t1.hidden = false  and t1.hidden is not null ) ").findList();
    
    
    for (SqlRow row : rows) {
        // do something with each row here, use methods such 
        // as getString("fieldname") for retrieving data  
        // (from SqlRow API)
    }
    

    【讨论】:

    • 不幸的是,就像我说的那样,我真的不想链接对象,因为 Ebean 在检索链接对象方面有点太擅长了,而且几乎所有的安全性都在“DAO”层中。这意味着很容易犯错误,例如,在不检查策略的情况下检索一个对象并通过该引用访问数据。 --edit:我很清楚这不是为 Ebean 设计的,但现在我一直在努力让它像那样工作。
    • 看一下 SQL 语句,它们只从表 A 中获取字段 :) 加入 B 只是为了检查隐藏字段。与您在示例 SQL 中显示的完全一样
    • 哎呀,我明白了,你甚至不想使用A 对象 :) 检查我上次的编辑,我认为 SqlQuery 就是你要找的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多