对于一个项目,我们开始研究持久性功能以及我们希望如何实现它.目前我们正在考虑保持清洁架构,可能是为了洋葱架构.因此,我们想要定义一个新的外层,持久层所在的外层.
我们正在研究使用SQLite作为数据存储的各种ORM解决方案(我们似乎正在融合到Entity Framework),我们遇到了一个障碍:如何管理ID并处理某些集合中的添加/删除或在不同集合之间移动某些实例集合.
在我们的’洋葱’的核心,我们想要保留我们的POCO对象.因此,我们不希望在业务对象中添加某种“ID”属性.只有在持久层内,我们才能拥有具有对象ID的类.由于这种分离:
>如何从某个集合中删除业务对象导致从SQLite数据库中删除一行?
>更复杂(至少我认为是这样),POCO实例应该如何从1个集合移动到另一个集合导致SQLite数据库的外键被更改? (而不是删除行并使用相同的值重新创建它)
环顾互联网我还没有找到一个实现清洁架构设计中的持久层的实现.大量的高级图表和“仅向内依赖”,但没有源代码示例来演示.
到目前为止我们提出了一些可能的解决方案:
>在持久层内的POCO实例与其代表性的“数据库模型对象”(具有ID等)之间进行一些查找.保存项目状态时,业务模型对象将与此数据库模型对象匹配,并相应地更新匹配的状态.然后该对象被持久化.
>加载项目时,持久层会返回业务对象的装饰器对象,这些对象将业务对象添加ID,只有通过将对象强制转换为该装饰器类才能在持久层中看到该对象.然而,这阻止我们定义密封的POCO对象,并且似乎打破了Clean Architecture设计理念.
由于有效地将内存中的业务对象加倍,选项1在内存中看起来很昂贵.选项2似乎是最优雅的,但正如我所写:它感觉它打破了清洁架构.
那里有更好的替代品吗?我们是否应该选择备选方案2并将清洁架构作为指导而非规则?有人能指出我们在代码中的一个工作示例(我确实在https://github.com/luisobo/clean-architecture找到了一个iOs示例,但由于我不懂语言,因此无法用它做很多事情).
最佳答案 首先,现实世界中的一切都有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可帮助您保持具有不同职责的良好设计.