C# 将不可变对象持久化到关系数据库
我看到一些面向对象专家建议域对象(POCO)应该是不可变的 也就是说,它们的状态应该在构造时完全确定,对状态的更改应该需要创建一个全新的实例 但是,假设我使用ORM持久化到关系数据库——我如何确定要持久化的属性,以及如何基于数据库中的数据重建域对象 例如,假设我想将此对象写入数据库:C# 将不可变对象持久化到关系数据库,c#,domain-driven-design,relational-database,immutability,C#,Domain Driven Design,Relational Database,Immutability,我看到一些面向对象专家建议域对象(POCO)应该是不可变的 也就是说,它们的状态应该在构造时完全确定,对状态的更改应该需要创建一个全新的实例 但是,假设我使用ORM持久化到关系数据库——我如何确定要持久化的属性,以及如何基于数据库中的数据重建域对象 例如,假设我想将此对象写入数据库: class User { private string _emailAddress; public User(string emailAddress, string password) {
class User
{
private string _emailAddress;
public User(string emailAddress, string password)
{
// ... generate hash & seed
_emailAddress = emailAddress;
}
public string PasswordHash { get; private set; }
public string PasswordSeed { get; private set; }
public bool ValidatePassword(string password)
{
// validate it against the stored hash
}
}
在上面的示例中,我希望存储对象的状态,并在以后检索它。这意味着存储PasswordHash、PasswordSeed和EmailAddress
但是班级的结构阻止了我这么做
- PasswordHash和PasswordSeed-我可以存储它们,但是当我想从数据库中读回它们并重建对象时会发生什么?没有可以传递它们的构造函数参数,没有它们我甚至无法构造对象,因为必须提供“password”,我不知道原始密码是什么。我无法设置“PasswordHash”或“PasswordSeed”属性,因为它们是“私有集”
- EmailAddress-我无法存储它,因为即使它是对象状态的一部分,它也被标记为私有,无法在内部访问
潜在的问题似乎是关系数据库没有封装的概念。表中的每一列都是“公共的”,每一个值都是“可变的”
那么,这是否意味着如果我要有一个不可变的域模型,就必须完全抛弃关系映射?或者是否有一些我还不知道的众所周知的策略来解决这个问题?您可以读入对象的序列化和反序列化,并以这种方式将数据存储在数据库中(其中一些是特定于语言的,因此可能无法跨语言工作)。如果要存储所有已创建的字段。这将解决您的密码问题,但如果有人访问并反序列化您的实例并获取明文密码(如果它存储在对象中),则会带来安全风险
下面是一个基本的示例:私有字段也可以序列化-请参阅 在您的情况下,您希望将值序列化为DB,并将其读回…
有几种方法可以做到这一点,例如:
- 实现2个静态方法作为类成员,可以访问所有内部/私有字段,从而序列化和重构类中的任何字段
- 实现一些序列化/反序列化接口,可以将其用作静态方法的参数,以减少序列化/反序列化进程与类之间的依赖关系
在静态方法中,您可以自由选择在数据库中保存哪些字段以及保存方式(二进制、XML或作为每个字段的一列等)。只需相应地实现序列化/反序列化接口。首先,域对象应该是不可变的说法是错误的。
只有值对象应该是不可变的。用户很可能是一个实体 通常ORM使用一些技巧来解决这个问题 例如,NHibernate利用代理库,像是用动态创建的类对映射的每个类进行静默子类化。为此,它为每个方法附加处理程序,这些方法检查状态是否已被修改,并触发脏实体的持久更改
NHibernate强制映射对象具有受保护的、无参数的构造函数,所有属性和方法都是可重写的。对象通过此构造函数创建为“空”,状态通过重写的属性设置。我建议您将域层与数据层分离。换言之:
问题解决了!编写所有映射代码似乎是一件痛苦的事情(您需要对其进行测试,因为映射非常容易出错),但最终,它将解决试图用一个类来实现两个目的所带来的头痛问题。我不确定我是否理解这个问题。。。哪些属性已计算,哪些需要存储?对不起,我不擅长解释这些东西:P我更新了问题。现在清楚一点了吗?是的-看看我的答案。。。如果您需要进一步的信息/想法,只需评论:-)NHibernate。可以分配私有/受保护的属性/字段。编写另一个构造函数有什么问题?有趣的解决方案。安全性不会成为问题,因为密码不会被存储,但会在构建对象时立即散列。但是,此解决方案适用于二进制流,而不是关系存储。我正在寻找一种持久化到关系数据库(例如SQL Server)的方法,如果