【问题标题】:Coding Style: Is it acceptable to make further queries from within model classes?编码风格:从模型类中进行进一步查询是否可以接受?
【发布时间】:2012-02-05 03:26:59
【问题描述】:

我有一个模型类Alert与另一个模型类Occurrence有一对多的关系,如下:

@Entity public class Alert extends Model
{
  public String name;

  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="alert")
  public List<Occurrence> occurrences;
}

@Entity public class Occurrence extends Model
{
  @ManyToOne
  public Alert alert;

  @Column(nullable=false)
  public Date alertTime;
}

我有一个视图,它在一个简单的表格中列出了警报,该表格应该有一个标记为“今天发生”的列,并计算今天发生了多少次警报(alertTime)。

我似乎无法找到仅使用 Alert 模型类中的 JPA/Hibernate 注释来执行此操作的方法,并且由于我列出了警报,因此我不知道将计数包含在其中的干净方法每个Alert 对象。

所以现在我想知道是否可以简单地从Alert 模型类本身的查询警报的出现,如下所示:

@Entity public class Alert extends Model
{
  public String name;

  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="alert")
  public List<Occurrence> occurrences;

  @Transient
  public long getOccurrencesToday()
  {
    return Occurrence.count(
      "alert = ? and alertTime >= ?",
      this, new DateMidnight().toDate());
  }
}

我的问题是:从模型类中查询数据库是否被认为是不好的形式?

第二个问题是:我是不是以错误的方式处理这个问题?有没有更好的方法来实现我错过的最终结果?

【问题讨论】:

  • 澄清:我对从模型类中执行查询的担忧是,当控制器类缓存模型实例时,它可能无法获得预期的行为。也就是说,控制器认为它正在从缓存中获取稍微旧的数据,而实际上每次都从数据库中获取某些属性。此外,重复访问该属性的视图可能会导致不明显的性能损失。

标签: jpa playframework


【解决方案1】:

在域模型类中进行查询应该是正确的方法,因为这些查询与该模型相关。为此,我认为您的代码没有任何问题。

根据 Play 的理念,领域对象不仅仅是一个数据对象。它应该在里面包含一定的业务逻辑。事实上,游戏并不鼓励纯数据对象。查看更多http://www.playframework.org/documentation/1.2.4/model

【讨论】:

  • 同意“贫血对象模型”这件事——这一直是我的烦恼。我从示例代码中省略了域逻辑以保持它的小。 :)
  • 没有什么可以阻止您将结果缓存在模型对象中。只需使用您在控制器中使用的相同缓存方法
【解决方案2】:

虽然您的方法很诱人,但它很危险,因为您实际上是将逻辑放入“getter”(getOc​​currencesToday()) 中,您可能会通过 ${alert.occurrencesToday} 访问它

getter 应该始终没有副作用。

我会把它改成

@Entity public class Alert extends Model
{
  public String name;

  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="alert")
  public List<Occurrence> occurrences;

  @Transient public Long occurrencesToday = null;

  public void populateOccurrencesToday()
  {
    occurrencesToday = Occurrence.count(
      "alert = ? and alertTime >= ?",
      this, new DateMidnight().toDate());
  }
}

然后在您的控制器中,遍历所有警报 您将渲染并执行 populateOccurrencesToday() 方法。 如果您现在将对象存储在缓存中,则其数据将是一致的。

【讨论】:

  • 非常感谢您的回答。我明白你的意思,但想知道 SELECT COUNT 查询是否真的有资格作为副作用......嗯......此外,虽然您的解决方案很简洁,但它确实需要将结果迭代两次。不过,我认为这是真正的答案。再次感谢!
  • 问题不在于 SELECT COUNT 本身,而在于您将其放入 getter 中。您无法轻松预测调用此 getter 的频率以及执行代码的频率。例如如果你有这样的查看代码 #{if object.occurrencesToday} #{if object.occurrencesToday == 0} 我们今天没有出现 #{/if} #{else} #{if object.occurrencesToday == 1 } 这种情况每天发生一次 #{/if} #{else} 这种情况会发生 ${object.occurencesToday} 次 #{/else} #{/else} #{/if} 这很难甚至无法判断play 多久调用一次方法/db。
猜你喜欢
  • 1970-01-01
  • 2011-06-18
  • 2010-10-29
  • 1970-01-01
  • 2013-05-21
  • 2012-08-24
  • 1970-01-01
  • 1970-01-01
  • 2014-06-09
相关资源
最近更新 更多