将JPA实体暴露给表示层

时间:2015-12-14 02:10:45

标签: java hibernate jpa

在表示层中使用JPA实体似乎微不足道。

XHTML:

<h:outputText value="#{catalog.item.name}:"/>

控制器:

@SessonScoped
@ManagedBean
class Catalog {
    @EJB
    private Item item = null;
    public Item getItem(){
        ...
    }
    ....
}

实体JPA:

@Entity
class Item {
    @Id
    private Integer identifier;
    @Column
    private String name;
    //gets and sets
}

中/大系统是否有任何限制?它是否规模?有没有陷阱

3 个答案:

答案 0 :(得分:1)

JSF和Java EE专家,如Bauke Scholtz和Adam Bien建议在表示层使用实体,而不是制作一些通常无用的中间对象。

我将在下面引用它们,但请注意,它们有时会使用术语&#34; DTO&#34; (数据传输对象)用于描述某些设计在实体和表示层之间引入的中间对象。

Adam Bien写道:

  

另一方面,考虑到专用的DTO层作为投资,很少会得到回报并且经常导致过度设计和臃肿的架构。在开始时,DTO将与您的域层相同 - 没有任何阻抗不匹配。如果您很幸运,那么随着时间的推移您将获得一些差异。特别是对于像Java EE 6这样的轻量级平台,DTO的引入是自下而上的,而不是自上而下的方法。&#34; ~ How evil are Data Transfer Objects

(请注意,上面引用的文章还建议何时 适合使用中间对象:&#34;引入专用DTO以适应不兼容的域层是完全有效的。 &#34)

Bien的描述对我来说非常有意义。已经开展了与实体相同的中间对象的项目,因为&#34;它的设计很好,因为它具有低耦合性。一直是一个巨大的,滑稽的浪费时间。浪费时间将DTO转换为实体是可能的,并且需要良好的团队纪律以确保开发人员根据某些项目策略对待DTO和实体,例如,在哪些对象上执行验证,业务逻辑等。

Bauke Scholtz写道:

  

但是,对于普通的网络应用,您不需要DTO。您已经在使用JPA实体了。您可以继续在JSF bean / view中使用它们。这个问题已经表明你根本不需要DTO。您没有被某些特定的业务限制所阻止。然后,您不应该搜索设计模式,以便可以将其应用于项目。您应该以过于复杂/不可维护的代码的形式搜索实际问题,以便您可以为其寻找/找到合适的设计模式。 ~ How to use DTO in JSF + Spring + Hibernate

答案 1 :(得分:0)

从技术角度来看,没有什么可以阻止您查询数据层中的实体并允许它们一直流经业务层并进入表示层。事实上,对于非常小规模的应用或概念工作的证明,它是一个合理的解决方案。

该方法的问题在于,您现在在域实体类和视图之间存在紧密耦合的关系。对您的域模型的任何更改都会立即影响您的视图,或者任何视图要求更改都可能立即影响您的域模型在任何复杂的应用中都不希望这种紧耦合。

答案 2 :(得分:0)

JPA实体是具有解耦状态(DETACHED,MANAGED)的普通旧Java对象,在表示层中使用它们没有问题。

在大多数应用程序中,它不会将JPA实体的字段复制到提供相同状态的其他表示对象。

您可以将JPA实体与接口结合使用,这样只有在真正需要时才能引入其他传输对象,并且如果没有现有的jpa实体符合目标视图的要求。

对于与接口的关系,需要@OneToMany,@ OneToOne或@ManyToOne的targetType属性(例如@OneToMany(targetType = SomeJPAEntity.class))。

以下是Java FX应用程序的持久性和表示层中使用的Items实体的一些示例代码:

// Service definition for obtaining IItem objects.
public interface IItemService {
    IItem getItemById(Integer id);
    IItemWithAdditionalState getItemWithAdditionalStateById(Integer id);
}

// Definition of the item. public interface IItem { StringProperty nameProperty(); ObservableList subItems(); List getSubItems(); }

// Definition for the item with additional state. public interface IItemWithAdditionalState extends IItem { String getAdditionalState(); }

// Represents a sub item used in both the persistence and the presentation layer. @Table(name = SubItem.TABLE_NAME) @Entity public class SubItem extends AbstractEntity implements ISubItem, Serializable { public static final String TABLE_NAME = "SUB_ITEM"; }

// Represents an item used in both the persistence and the presentation layer. @Access(AccessType.PROPERTY) @Table(name = Item.TABLE_NAME) @Entity public class Item extends AbstractEntity implements IItem, Serializable {

public static final String TABLE_NAME = "ITEM"; private StringProperty nameProperty; private String _name; // Shadow field for lazy loading of java fx properties. private ObservableList<ISubItem> subItems = FXCollections.observableArrayList(); public StringProperty nameProperty() { if (null == nameProperty) { nameProperty = new SimpleStringProperty(this, "name"); } return nameProperty; } public String getName() { return null == nameProperty ? _name : nameProperty.get(); } public void setName(String name) { if (null == nameProperty) { _name = name; } else { _name = null; nameProperty.set(name); } } @Override public ObservableList<ISubItem> subItems() { return subItems; } @JoinColumn(name = "ID") @OneToMany(targetEntity = SubItem.class) @Override public List<ISubItem> getSubItems() { return subItems; } public void setSubItems(List<ISubItem> subItems) { this.subItems.setAll(subItems) }

}

//新添加的演示文稿数据传输对象,用于匹配特殊视图的要求。 公共类ItemWithAdditionalState extends Item实现IItemWithAdditionalState {

String getAdditionalState();

}