[英]Entity Framework - Saving a snapshot of a document in a SQL database
背景信息我正在使用EF6,可以随意更改数据库。
我今天遇到了这个问题。 说我有:
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Address
{
public int Id { get; set; }
public int CompanyId { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
}
public class Invoice
{
public int Id { get; set; }
public int CompanyId { get; set; }
public int AddressId { get; set; }
public bool IsCompleted { get; set; }
}
允许用户更新Company
和Address
。 还允许用户更新Invoice
。 但是由于是财务文件,因此如果用户将IsCompleted
标记为true,则必须以某种方式保存该地址的快照。
当前,它是通过以下方式完成的:
public class Invoice
{
public int Id { get; set; }
public int CompanyId { get; set; }
public int AddressId { get; set; }
public bool IsCompleted { get; set; }
//Auditing fields
public string CompanyName { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
}
我认为这很难遵循。 我刚在想:
选项1:将审核保存到自己的审核表中:
public class Invoice
{
public int Id { get; set; }
public int CompanyId { get; set; }
public int AddressId { get; set; }
public bool IsCompleted { get; set; }
//Null if IsCompleted = false.
public DateTime? CompletedTimeStamp { get; set; }
}
public class CompanyAudit
{
public int CompanyId { get; set; }
public string Name { get; set; }
public DateTime TimeStamp { get; set; }
}
public class AddressAudit
{
public int AddressId { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public DateTime TimeStamp { get; set; }
}
但是,如果我们确实更改了Company和Address的架构,那么这似乎要创建许多表,并且需要进行大量工作。 另外,它也不是很健壮。 没有大量的接线,我无法将其用于其他文档。 但是,这是我主要在互联网上发现的东西。 每个表一个审计表。
选项2:将所有审核保存到同一表中:
public class Audit
{
public int DocumentId { get; set; }
public string DocumentType { get; set; }
public string JsonData { get; set; }
public DateTime TimeStamp { get; set; }
}
但是,这似乎不是很标准。 我以前从未将Json数据保存到SQL数据库。 这不好吗? 如果是这样,可能会出什么问题?
我应该选择选项1还是选项2?
假设您使用的是SQL Server,建议您为该作业创建一些可序列化XML的DTO ,并使用XML数据类型将XML存储在专用列中 。
我已经走了完全相同的道路。 我们需要在已打印出数据时保存快照,其中涉及许多表,在该过程中可能会重复这些快照。
要求与评估
我们不想合并其他技术(例如,由Andreas提出的文件系统或某些NoSQL /文档数据库),而是将所有内容存储在SQL Server中,否则会带来复杂的备份方案,部署,维护等。
我们想要一些容易理解的东西。 新的开发人员应该熟悉所使用的技术。 架构不应受到太大影响。
对于序列化,有几个选项: XML , JSON , BinaryFormatter , DataContractSerializer , 协议缓冲区。 ..我们的要求:易于版本控制(用于添加的属性或关系),可读性,与SQL Server的一致性。
使用所有提到的格式应该可以轻松地进行版本控制。 可读性:XML和JSON在这里胜出。 与SQL Server的一致性: SQL Server本身支持XML ,这是我们的选择。
履行
我们做了几件事:
与现有实体并排在我们的数据库项目中创建其他DTO ,而不是用于EF,而是用于XML序列化。 它们使用XmlAttributes进行注释,类似于一个复杂的自包含结构,其中包含保存文档数据所需的一切。 根InvoiceSnapshot
类具有Parse
和ToXml
方法以支持序列化。
在需要时更新我们的实体以包括快照:
public string InvoiceXml { get; set; } public InvoiceSnapshot Invoice { get { return this.InvoiceXml != null ? InvoiceSnapshot.Parse(this.InvoiceXml) : null; } set { this.InvoiceXml = value != null ? value.ToXml() : null; } }
更新实体配置以创建XML列,并忽略InvoiceSnapshot
属性:
public class InvoiceEntityConfig : EntityTypeConfiguration<InvoiceEntity> { public InvoiceEntityConfig() { this.Property(c => c.InvoiceXml).HasColumnType("xml"); this.Ignore(c => c.Invoice); } }
修改我们的业务对象,以便它们从实体(可编辑状态)或XML-DTO(快照,只读状态)加载自身。 我们在有助于简化流程的两个界面上都使用接口。
进一步的步骤
选项2
但
更好的方法是将生成的发票(pdf)及其所有还原版本存储在普通文件中。
您仍然可以使用Invoice表,但是如果某些客户数据发生更改并且用户重新打印了较旧的文档,则无需担心。
要存储生成的文档,几乎就像将模型存储在JsonData中一样,但是您不需要保护模板和模板生成器的版本。
Option1只是蛮力的,最好用“事件存储”,“事件源”和“查询和命令”模式发布。
public class Document //or DocumentFile
{
public int DocumentId { get; set; }
public string DocumentType { get; set; }
public string FilePath { get; set; }
[Index]
public String Owner { get; set;} //exp. "Customer:Id", "Contact:Id" maybe just int
[Index]
public String Reference { get; set; } //exp. "Invoice:Id", "Contract:Id" maybe just int
public DateTime TimeStamp { get; set; } //maybe int Reversion
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.