如何打破循环依赖并达到规范化?

huangapple go评论73阅读模式
英文:

How to break a circular depencency and be canonic?

问题

我在两个模型之间存在循环依赖,但从使用角度来看,这并不是一个真正的循环依赖。

  • 一个建筑物归某个所有者所有。
  • 一个租户住在某个建筑物里。

根据用户的类型,与建筑物的关系不同。

public enum UserType
{
    TENANT,
    OWNER
}

public class User extends Model
{
    @ManyToOne
    private Building building;

    private UserType type;
}

public class Building extends Model
{
    @ManyToOne
    private User owner;
}

这被视为真正的循环依赖吗?我该如何避免这种情况?

编辑:

我在Play Framework中使用依赖注入(使用Guice),但这也让我很头疼。代码可以编译,但无法运行。

public class BuildingRepository
{
    @Inject
    private UserRepository userRepository;

    private final Finder<Long, Building> find = new Finder<>(Building.class);

    public void save(Building building)
    {
        building.save();
    }

    public void update(Building building)
    {
        building.update();
    }

    public boolean delete(Building building)
    {
        // 检查建筑物内是否有租户
        if (userRepository.countByBuilding(building) > 0)
        {
            return false;
        }
      
        return building.delete();
    }

    public List<Building> findFor(User user)
    {
        if (user.getType() == UserType.OWNER)
        {
            return find.query().where()
                .eq("owner.id", user.getId())
                .findList();
        }
   
        return new ArrayList<>();
    }
}

public class UserRepository
{
    @Inject
    private BuildingRepository buildingRepository;

    private final Finder<Long, User> find = new Finder<>(User.class);

    public void save(User user)
    {
        user.save();
    }

    public void update(User user)
    {
        user.update();
    }

    public boolean delete(User user)
    {
        if (user.getType() == UserType.OWNER)
        {
            // 移除建筑物上的所有者
            for (Building building : buildingRepository.findFor(user))
            {
                if (user.equals(building.getOwner()))
                {
                    building.setOwner(null);
                    buildingRepository.update(building);
                }
            }
        }

        return user.delete();
    }

    public int countByBuilding(Building building)
    {
        return find.query().where()
            .eq("building.id", building.getId())
            .eq("status", true)
            .findCount();
    }
}
英文:

I have a circular dependency between 2 models but this is not a real one in the point of view of usage.

  • A building is owned by an owner
  • A tenant lives in a building

Depending on the type of the user, the relation with the building differs.

public enum UserType
{
TENANT,
OWNER
}

User:

public class User extends Model
{
@ManyToOne
private Building building;
private UserType type;
}

Building:

public class Building extends Model
{
@ManyToOne
private User owner;
}

Is it considered a real circular dependency? How should I avoid that?

Edit:

I have dependency injections with Play Framework (using Guice) that also give me headache. The code compiles but it doesn't run.

public class BuildingRepository
{
@Inject
private UserRepository userRepository;
private final Finder&lt;Long, Building&gt; find = new Finder&lt;&gt;(Building.class);
public void save(Building building)
{
building.save();
}
public void update(Building building)
{
building.update();
}
public boolean delete(Building building)
{
// check if there is tenants in the building
if (userRepository.countByBuilding(building) &gt; 0)
{
return false;
}
return building.delete();
}
public List&lt;Building&gt; findFor(User user)
{
if (user.getType() == UserType.OWNER)
{
return find.query().where()
.eq(&quot;owner.id&quot;, user.getId())
.findList();
}
return new ArrayList&lt;&gt;();
}
}

The UserRepository uses the BuildingRepository but only for a specific type of user.

public class UserRepository
{
@Inject
private BuildingRepository buildingRepository;
private final Finder&lt;Long, User&gt; find = new Finder&lt;&gt;(User.class);
public void save(User user)
{
user.save();
}
public void update(User user)
{
user.update();
}
public boolean delete(User user)
{
if (user.getType() == UserType.OWNER)
{
// remove the owner on the buildings
for (Building building : buildingRepository.findFor(user))
{
if (user.equals(building.getOwner()))
{
building.setOwner(null);
buildingRepository.update(building);
}
}
}
return user.delete();
}
public int countByBuilding(Building building)
{
return find.query().where()
.eq(&quot;building.id&quot;, building.getId())
.eq(&quot;status&quot;, true)
.findCount();
}
}

答案1

得分: 1

警告可能来自于JSON序列化。如果您直接将这些对象映射到JSON,那么就有可能在租户类的楼宇构建中添加所有者的构建。如果所有者住在自己的楼宇中,这是有道理的。您理论上可能会得到这样的结构:

{
  "user": {
    "building": {
      "owner": {
        "building": {
          "owner": {
            "building": {
              "owner": {
                "building": {
                  "owner": {
                    // ...
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

您可以通过不递归序列化建筑物的所有者来修复JSON递归。

public class Building extends Model {
    @ManyToOne
    @JsonIgnore
    private User owner;
}

对于实际需要所有者信息的情况,您可以创建DTO类,只包括您需要的信息:

public class BuildingDTO {
    private String ownerName;
}

编辑:

要修复存储库中的循环,您可以像这样做:

public class SafeDeleteService {
    @Inject
    private UserRepository userRepository;
    @Inject
    private BuildingRepository buildingRepository;

    public boolean safeDelete(User user) {
        if (user.getType() == UserType.OWNER) {
            // 删除建筑物上的所有者
            for (Building building : buildingRepository.findFor(user)) {
                if (user.equals(building.getOwner())) {
                    building.setOwner(null);
                    buildingRepository.update(building);
                }
            }
        }

        return userRepository.unsafeDelete(user);
    }
}

public class UserRepository {
    public boolean unsafeDelete(User user) {
        return user.delete();
    }
}
英文:

The warning comes probably from the JSON serialization. If you use these objects to map directly to json, there's nothing stopping from adding the building of an owner as the building of the tenant class. Which makes sense, if the owner lives in his own building. You could theoretically end up with a structure:

{
user: {
building: {
owner: {
building: {
owner: {    
building: {
owner: {
...
}

You can fix the JSON recursion by not serializing the owner of the building recursively.

public class Building extends Model
{
@ManyToOne
@JsonIgnore
private User owner;
}

For cases that you actually need the owner information, you can create DTO classes to include just the information you need:

public class BuildingDTO
{
private String ownerName;
}

Edit:

To fix the cycle in the repositories, you could do something like this:

public class SafeDeleteService
{
@Inject
private UserRepository userRepository;
@Inject
private BuildingRepository buildingRepository;
public boolean safeDelete(User user)
{
if (user.getType() == UserType.OWNER)
{
// remove the owner on the buildings
for (Building building : buildingRepository.findFor(user))
{
if (user.equals(building.getOwner()))
{
building.setOwner(null);
buildingRepository.update(building);
}
}
}
return userRepository.unsafeDelete(user);
}
}
public class UserRepository
{
public boolean unsafeDelete(User user)
{
return user.delete();
}
}

huangapple
  • 本文由 发表于 2020年9月2日 17:17:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/63702467.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定