玩!框架数据库继承

Play! Framework database inheritance

请注意:本人初玩框架

信息:

我花了几个小时寻找有关使用 Play Framework 继承的体面教程或解释,

然而每个示例似乎都省略了整个示例,这造成了混淆,因此也是这个问题的原因。

郑重声明,我使用的是 MariaDB(又称 ~MySQL)

研究与文献:

但是,我可能完全误解了,但是示例提供了将不同名称的列连接到未提及的 table

Problem/Question:

我需要利用继承(即外键等)创建一个数据库,具体如何,有解释,我可以这样做吗?

数据库模式:

我目前拥有的:

型号:用户

import io.ebean.Finder;
import io.ebean.Model;
import play.data.validation.Constraints;

import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
//@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class User extends Model {

    @Id
    @GeneratedValue
    private Long userId;

    @Constraints.MaxLength(50)
    private String name;
    @Constraints.MaxLength(100)
    private String surname;

    @Constraints.Required
    @Constraints.MinLength(8)
    private String password;

    @Constraints.Email
    @Constraints.Required
    private String email;

    @Constraints.Required
    @Constraints.MaxLength(10)
    @Constraints.MinLength(10)
    @Constraints.Pattern("[0]\d{2}[- ]{0,1}\d{3}[- ]{0,1}\d{4}")
    private String cellNumber;

    private Boolean emailVerified = false;
    private String token;

    public static Finder<String, User> find = new Finder<String, User>(User.class);

    public User(){}

    public User(@Constraints.MinLength(10) @Constraints.MaxLength(10) Long userId, String name, String surname, @Constraints.Required String password, @Constraints.Email @Constraints.Required String email, @Constraints.Required @Constraints.Pattern("[0]\d{2}[- ]{0,1}\d{3}[- ]{0,1}\d{4}") String cellNumber, Boolean emailVerified) {
        this.userId = userId;
        this.name = name;
        this.surname = surname;
        this.password = password;
        this.email = email;
        this.cellNumber = cellNumber;
        this.emailVerified = emailVerified;
    }

型号:职员

import io.ebean.Finder;
import play.data.validation.Constraints;

import javax.persistence.Entity;
import javax.persistence.Id;

/**
 * Created by cybex on 2017/07/13.
 */

@Entity
public class Staff extends User {

    @Id
    private Long userId;

    @Constraints.Required
    private Boolean isKitchenStaff;

    public static Finder<String, Staff> find = new Finder<String, Staff>(Staff.class);

    public Staff(@Constraints.Required Long userId, String name, String surname, @Constraints.Required String password, @Constraints.Email @Constraints.Required String email, @Constraints.Required @Constraints.Pattern("[0]\d{2}[- ]{0,1}\d{3}[- ]{0,1}\d{4}") String cellNumber, String userId1, @Constraints.Required Boolean isKitchenStaff) {
        super(userId, name, surname, password, email, cellNumber, false);
        this.isKitchenStaff = isKitchenStaff;
    }
}

型号:客户

import io.ebean.Finder;
import play.data.validation.Constraints;
import javax.persistence.Entity;

@Entity
public class Customer extends User {

    @Constraints.Required
    private Address address;
    private Boolean isStudent = false;

    public Customer(){}

    public Customer(Long userId, String name, String surname, String email, String cellNumber, String password, String userId1, @Constraints.Required Address address, Boolean isStudent) {
        /*super(userId, name, surname, email, cellNumber, password, false);*/
        this.address = address;
        this.isStudent = isStudent;
    }

    public static final Finder<String, Customer> find = new Finder<String, Customer>(Customer.class);
}

型号:地址

import io.ebean.Finder;
import io.ebean.Model;
import play.data.validation.Constraints;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

/**
 * Created by cybex on 2017/07/13.
 */

// TODO: 2017/07/13 Add fields for suburb and city for larger projects
@Entity
public class Address extends Model {

    @Id
    @Constraints.Required
    @GeneratedValue
    @Constraints.Max(15)
    private Long addressId;
    @Constraints.Required
    private String unitNumber;
    @Constraints.Required
    private String streetName;
    private String communityName;
    private Boolean isCommunity;

    public Address(@Constraints.Required Long addressId, @Constraints.Required String unitNumber, @Constraints.Required String streetName, String communityName, Boolean isCommunity) {
        this.addressId = addressId;
        this.unitNumber = unitNumber;
        this.streetName = streetName;
        this.communityName = communityName;
        this.isCommunity = isCommunity;
    }

    public static Finder<String, Address> find = new Finder<String, Address>(Address.class);
}

建议添加:

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

但是它会导致错误:

CreationException: Unable to create injector, see the following errors:

1) Error injecting constructor, java.lang.NullPointerException

请参阅 here 了解完整堆栈跟踪

问题(和 TL;DR):

TL;DR:一个基本的全功能的,有解释的,玩吧!表示上面显示的数据库模式的框架模型。

不支持继承类型(截至 2017 年 8 月 18 日)

Play 使用 Ebean ORM,目前不支持 InheritanceType.TABLE_PER_CLASSInheritanceType.JOINED。这是一个悬而未决的问题 listed here

我已经验证过了。我复制了你的代码,并用 InheritanceType.TABLE_PER_CLASS 运行 复制了它。 Play 创建了用户和地址 table,但没有创建子 table、员工和客户。

参考,消除错误...

Error injecting constructor, java.lang.NullPointerException

...您需要将 @Entity 注释添加到 User,以及 InheritanceType:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class User extends Model {
...

为了完成,您还需要删除...

private Long userId;

...来自 Staff,因为它继承自 User。


你有什么选择?

1) 您可以将项目重组为 use hibernate with Play,它支持 InheritanceType.TABLE_PER_CLASSInheritanceType.JOINED

2) 使用InheritanceType.SINGLE_TABLE。此方法将用户、客户和员工数据存储在一个 table,User.它可能不是您理想的实现方式,但它会起作用:

如果您决定这样做,请注意...

The single table strategy maps all entities of the inheritance structure to the same database table. This approach makes polymorphic queries very efficient and provides the best performance.

But it also has some drawbacks. The attributes of all entities are mapped to the same database table. Each record uses only a subset of the available columns and sets the rest of them to null. You can, therefore, not use not null constraints on any column that isn’t mapped to all entities. That can create data integrity issues, and your database administrator might not be too happy about it. more on Inheritance Type comparisons

型号:用户

import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;

import com.avaje.ebean.Model;

import play.data.validation.Constraints;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "user_type")
public class User extends Model {

  @Id
  @GeneratedValue
  private Long userId;

  @Constraints.MaxLength(50)
  private String name;
  @Constraints.MaxLength(100)
  private String surname;

  @Constraints.Required
  @Constraints.MinLength(8)
  private String password;

  @Constraints.Email
  @Constraints.Required
  private String email;

  @Constraints.Required
  @Constraints.MaxLength(10)
  @Constraints.MinLength(10)
  @Constraints.Pattern("[0]\d{2}[- ]{0,1}\d{3}[- ]{0,1}\d{4}")
  private String cellNumber;

  private Boolean emailVerified = false;
  private String token;

  public static Finder<String, User> find = new Finder<String, User>(User.class);

  public User(){}

}

@DiscriminatorColumn(name = "user_type") 是您区分记录的方式。 user_type 用户记录的值为 null,客户记录的 customer,以及 staff 用于员工记录。

型号:职员

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

import play.data.validation.Constraints;

@Entity
@DiscriminatorValue("staff")
public class Staff extends User {

    @Constraints.Required
    private Boolean isKitchenStaff;

    public static Finder<String, Staff> find = new Finder<String, Staff>(Staff.class);

    public Staff() {}
}

模范客户:

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.OneToOne;

import play.data.validation.Constraints;

@Entity
@DiscriminatorValue("customer")
public class Customer extends User {

    @Constraints.Required
    @OneToOne(mappedBy = "customer")
    private Address address;
    private Boolean isStudent = false;

    public Customer(){}

    public static final Finder<String, Customer> find = new Finder<String, Customer>(Customer.class);
}

@OneToOne 添加到客户的地址映射。

模型地址:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;

import com.avaje.ebean.Model;

import play.data.validation.Constraints;

@Entity
public class Address extends Model {

    @Id
    @Constraints.Required
    @GeneratedValue
    @Constraints.Max(15)
    private Long addressId;
    @Constraints.Required
    private String unitNumber;
    @Constraints.Required
    private String streetName;
    private String communityName;
    private Boolean isCommunity;

    @OneToOne
    @JoinColumn(name = "user_id")
    private Customer customer;

    public Address(){}

    public static Finder<String, Address> find = new Finder<String, Address>(Address.class);
}

@OneToOne 客户映射已添加到地址。

这是使用 Play 2.5.10 验证的。