对于一个项目,我们开始研究持久性功能以及我们希望如何实现它。目前我们正在考虑保持清洁架构,可能是为了洋葱架构。因此,我们想要定义一个新的外层,持久层所在的外层。
我们正在研究使用SQLite作为数据存储的各种ORM解决方案(我们似乎正在融合到实体框架),我们正在遇到障碍:如何管理ID并处理某些集合中的添加/删除或移动一些不同集合之间的实例。
在'洋葱'的核心,我们想要保留我们的POCO对象。因此,我们不希望在业务对象中添加某种“ID”属性。只有在持久层内,我们才能拥有具有对象ID的类。由于这种分离:
环顾互联网我还没有找到一个在Clean Architecture设计中展示持久层的实现。大量的高级图表和“仅向内依赖”,但没有源代码示例来演示。 到目前为止我们提出了一些可能的解决方案:
由于有效地将内存中的业务对象加倍,选项1在内存中看起来很昂贵。选项2似乎是最优雅的,但正如我所写:它感觉它打破了清洁架构。
那里有更好的替代方案吗?我们是否应该选择备选方案2并将清洁架构作为指导而非规则?有人能指出我们在代码中的一个工作示例(我确实在https://github.com/luisobo/clean-architecture找到了一个iOs示例,但由于我在语言中没有识字,因此无法用它做很多事情。)
答案 0 :(得分:2)
正如其他人在评论中提到的,ID是应用程序的自然部分,并且通常在持久性以外的其他部分中是必需的。 因此,不惜一切代价避免使用ID会产生尴尬的设计。
然而,身份设计(在哪里使用哪些ID,在ID中放入什么信息,用户定义与系统生成等)是非常重要的,需要思考。
确定需要ID的内容的良好起点,以及域驱动设计的价值对象/实体区别。
如您所见,推理与您提出问题的技术观点截然不同。但这并不意味着您应该忽略框架(例如实体框架)所施加的约束。
如果您想深入讨论身份设计,我可以推荐"实施DDD"作者:Vaughn Vernon(第34节;独特身份"第5章 - 实体)。
注意:我不意味着建议您使用DDD。我只是认为DDD有一些关于ID设计的好指南。是否在这个项目中使用DDD是一个完全不同的问题。
答案 1 :(得分:0)
首先,现实世界中的一切都有ids。你有社会安全号码。汽车有他们的注册号码。商店中的商品具有EAN代码(和生产标识)。没有ids世界上没有任何东西可以工作(有点夸张,但希望你明白我的观点)。
与应用程序相同。
如果您的业务对象没有任何自然键(如社会安全号码),您必须有办法识别它们。一旦您复制对象或将其转移到进程边界上,您的应用程序将会失败。 因为那时它是一个新对象。 就像你克隆羊多莉一样。它是同一只羊吗?不,它是Mini-Dolly。
另一部分是当你构建复杂的结构时,你违反了得墨忒耳的法则。比如:
public class ForumPost
{
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public User Creator { get; set; }
}
public class User
{
public string Id { get; set; }
public string FirstName { get; set; }
}
使用该代码并调用时:
post.User.FirstName = "Arnold";
postRepos.Update(post);
你期望发生什么?您的论坛帖子repos是否应该突然对用户所做的更改负责?
这就是为什么ORM太可怕了。他们违反了良好的建筑。
回到ids。一个好的设计是使用 用户ID 。因为那时我们没有违反得墨忒耳的法律,并且仍然有很好的分离关注。
public class ForumPost
{
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public int CreatorId { get; set; }
}
所以结论是:
不要放弃ID,因为它会在尝试从将获取的所有副本中识别真实对象时引入复杂性。
在引用不同实体时使用ID可以帮助您保持良好的设计并承担不同的责任。