Java 如何将不同记录的数据添加到单个记录中?
如果没有时间,请看一看示例 我有两种类型的用户,临时用户和永久用户 临时用户将系统用作来宾,只需提供他们的姓名并使用它,但系统需要跟踪他们 永久用户是指已注册且永久的用户 一旦用户为自己创建了一个永久记录,我需要将用户作为客人时跟踪的所有信息复制到他的永久记录中 课程如下:Java 如何将不同记录的数据添加到单个记录中?,java,hibernate,jakarta-ee,hibernate-mapping,Java,Hibernate,Jakarta Ee,Hibernate Mapping,如果没有时间,请看一看示例 我有两种类型的用户,临时用户和永久用户 临时用户将系统用作来宾,只需提供他们的姓名并使用它,但系统需要跟踪他们 永久用户是指已注册且永久的用户 一旦用户为自己创建了一个永久记录,我需要将用户作为客人时跟踪的所有信息复制到他的永久记录中 课程如下: @Entity public class PermUser{ @Id @GeneratedValue private long id; @OneToMany private List
@Entity
public class PermUser{
@Id
@GeneratedValue
private long id;
@OneToMany
private List Favorites favorites;
....
}
@Entity
public class Favorites {
@Id
@GeneratedValue
private long id;
@OneToMany (cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
private List <FavoriteItems> items;
...
}
@Entity
public class FavoriteItems {
@Id
@GeneratedValue
private long id;
private int quantity;
@ManyToOne
private Ball ball;
..
}
@Entity
public class TempUser extends PermUser{
private String date;
....
}
*请注意,我需要找到一个解决方案,我不在乎是否尝试新的解决方案而不是克隆对象。
我有两个不同类的原因是
tempUser
几乎没有其他属性,我可能还需要将少数tempUser
的收藏夹添加到一个permUser
的收藏夹列表中。此外,如上所述,用户可能有许多不同的不相关的临时记录对此进行建模的一个好方法是创建类似于UserData
类的东西,以便TempUser
has-aUserData
和PermUser
has-aUserData
。您还可以使TempUser
具有-aPermUser
,尽管这将不太清楚。如果您的应用程序需要交替使用它们(这是您在使用继承时得到的),那么这两个类都可以实现一个接口,返回UserData
(或者在第二个选项中,getPermUser
,其中PermUser
返回自身)
如果您真的想使用继承,最简单的方法可能是使用“每个类的表层次结构”将其映射,然后使用直接的JDBC直接更新鉴别器列。从纯OO的角度来看,实例从一种类型变形为另一种类型,不管是否休眠,都没有意义。听起来您可能希望独立于对象的数据库表示重新考虑对象模型。例如,四轮驱动似乎更像是汽车的一种特性,而不是一种专门化 如果我遗漏了什么,请原谅,但我不认为
TempUser
和PermUser
应该是不同的类TempUser
扩展了PermUser
,这是一种“is-a”关系。显然,临时用户不是一种永久用户。您的问题没有提供足够的信息来证明它们是不同的——也许它们是同一个类,并且差异可以表示为几个新属性?例如:
@Entity
public class User{
@OneToMany(cascade = CascadeType.ALL)
private List Favorites favorites;
private boolean isTemporary;
....
}
某些控制器可以处理从临时到永久的“转换”,确保
istemporation=false
,并适当设置永久用户的其他属性。这将完全回避克隆问题,并使数据库更容易操作。对于问题的第2部分:
您正在使用CascadeType.ALL
作为收藏夹
关系。这包括CascadeType.REMOVE
,这意味着用户的删除操作将级联到该实体。因此,指定一个不包含CascadeType.REMOVE的CascadeType
值数组。
请参阅。,因为我同意之前的意见,即如果可能,您应该重新评估这些实体,但如果不可能,我建议您从数据库返回一个普通用户,然后将该用户分类为PermUser或TempUser,这两者都是用户的扩展,基于某些标准的存在。我也有同样的问题。我一直在阅读很多有趣的文章和问题,直到我有了足够的灵感
起初,我还希望为不同类型的用户提供子类。事实证明,这个想法本身就是一个设计缺陷:
不要使用继承来定义角色强>
更多信息请点击此处
将用户视为一个大容器,其中包含其他实体,如凭证、首选项、联系人、项目、用户信息等
记住这一点,您可以轻松地更改某些用户的能力/行为
当然,您可以定义许多用户可以扮演的角色。扮演相同角色的用户将具有相同的功能
如果您有许多相互依赖的实体/对象,那么您应该考虑一种构建机制/模式,以定义良好的方式设置特定的用户角色
一些想法:
如果你有一个供用户使用的建设者/工厂,那么你的另一个问题就不会那么复杂了
示例(非常基本,不要期望太多!)
public void changeUserRoleToPermanent(用户当前用户){
UserBuilder=新的UserBuilder();
builder.setRole(Role.PERMANENT);//builder在内部执行所有填充操作
//复制你想保留的东西
builder.setId(user.getId);
builder.setPrefences();
// ...
用户newRoleUser=builder.build();
newRoleUser=entityManager.merge(newRoleUser);
entitymanager.detach(当前用户);
//删除旧东西
entityManager.remove(currentUser.getAccountInfo());//已更改为不同的实现。。。
}
我承认,这是一些工作,但一旦基础设施准备就绪,您将有许多可能性!你可以很快地“发明”新东西
我希望我能传播一些想法。我为我糟糕的英语感到抱歉。我想说的可能不是OO,但希望会有效。我很高兴将PermUser和TempUser分开。不要扩展它,也不要将它们绑定到is-a关系中。所以我将在数据库中有两个单独的表,一个用于TempUser,一个用于PermUser,从而将它们视为两个单独的实体。许多人会发现这是多余的。。但请继续阅读。。。我们都知道。。有时候冗余是好的。。所以现在
1) 我不知道
@Entity
public class User{
@OneToMany(cascade = CascadeType.ALL)
private List Favorites favorites;
private boolean isTemporary;
....
}
public static <E> E copyObject(E dest, E src, Class<?> c) throws IllegalArgumentException, IllegalAccessException{
// TODO: You may want to create new instance of 'dest' here instead of receiving one as parameter
if (!c.isAssignableFrom(src.getClass()))
{
throw new IllegalArgumentException("Incompatible classes: " + src.getClass() + " - " + c);
}
if (!c.isAssignableFrom(dest.getClass()))
{
throw new IllegalArgumentException("Incompatible classes: " + src.getClass() + " - " + c);
}
while (c != null && c != Object.class)
{
for (Field aField: c.getDeclaredFields())
{
// We skip static and final
int modifiers = aField.getModifiers();
if ( Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers))
{
continue;
}
// We skip the fields annotated with @Generated and @GeneratedValue
if (aField.getAnnotation(GeneratedValue.class) == null &&
aField.getAnnotation(Generated.class) == null)
{
aField.setAccessible(true);
Object value = aField.get(src);
if (aField.getType().isPrimitive() ||
String.class == aField.getType() ||
Number.class.isAssignableFrom(aField.getType()) ||
Boolean.class == aField.getType() ||
Enum.class.isAssignableFrom(aField.getType()))
{
try
{
// TODO: You may want to recursive copy value too
aField.set(dest, value);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
c = c.getSuperclass();
}
return dest;
}
@MappedSuperclass
public abstract class User {
@Id
@GeneratedValue
private long id;
// Common properties and relationships...
@Entity
@Table(name="USER")
public class PermUser extends User {
// Specific properties
}
@Entity
@Table(name="PERMANENT_USER")
public class PermUser extends User {
public PermUser() {} // default constructor
public PermUser(List<TempUser> userData) {
final Set<Favorites> f = new LinkedHashSet<>();
// don't set the id
for(TempUser u : userData) {
this.name = u.getName();
// Shallow copy that guarants uniqueness and insertion order
// Favorite must override equals and hashCode
f.addAll(u.getFavorites());
}
this.favorites = new ArrayList<>(f);
// Logic to conciliate dates
}
}
Mapper mapper = new DozerBeanMapper();
mapper.map(tempUser.getFavorites(), user.getFavorites());
<mapping>
<class-a>my.object.package.TempUser</class-a>
<class-b>my.object.package.PermUser</class-b>
<!-- common fields with the same name will be copied by convention-->
<!-- exclude ids and fields exclusive to temp
<field-exclude>
<a>fieldToExclude</a>
<b>fieldToExclude</b>
</field-exclude>
</mapping>