我有一个关于对象视图中的自定义字段的架构问题。假设您有一个用户对象,其中包含一些基本信息,如名字,姓氏,......可供所有客户使用。
现在,我们经常会从客户那里得到一个问题,即为其域添加一些典型的自定义字段。我们现在的解决方案是一个xml数据列,其中存储了键值对。到目前为止一直没问题,但现在我们必须找到更具架构性的解决方案。
例如,现在,客户想要一个下拉列表,可以选择其自定义字段的值。我们仍然可以将选定的值存储在xml数据列中,但是我们在哪里存储所有这些下拉值......
我知道在sharepoint中你还可以添加下拉列表等自定义字段,我想知道如何处理这个问题。我想避免为客户创建自定义表,或者有一个包含90列的表(每个客户10个基本,然后10个),...
你明白了,它应该是通用的,并且能够在将来处理各种各样的问题。
我在想的是一个Table UserConfiguration,其中每个记录都有一个Customer键(我们数据库中的Channel),然后是一个FieldName列,一个FieldType列和一个Column列。列值应该是xml类型列,因为对于下拉列表,我们需要添加多个值。此外,每个值都可以附加额外的数据(而不仅仅是名称)。另一个问题是如何存储选定的值。我不喜欢在我的数据库中使用外键到xml的想法(在某处读取Azure无法处理这一切)。你是否只存储了值的名称(如果值从xml中消失了怎么办?)?
任何文档,关于此类问题的链接也会很棒。我正在尝试找到一种处理数据库中此类问题的设计模式。
答案 0 :(得分:4)
我想分两部分回答你的问题:
1)在数据库服务器中实现自定义字段
2)将自定义字段限制为值的枚举
虽然@Simon引用的question中讨论了1)的常见解决方案,但也许您正在寻找一些关于问题是什么以及为什么它还没有为我们解决的讨论。 / p>
如other question所述,没有完美的解决方案 但是这些好处/功能仍然需要在某个地方实现,因此应用程序通常负责数据完整性和类型安全 对于像这样的情况,人们已经创建了Object-Relation Mapping tools,但是,正如杰夫阿特伍德says,即使使用ORM也可能产生比解决的问题更多的问题。但是,你提到它应该是通用的并且能够处理未来的各种问题' - 这让我觉得ORM可能是你最好的选择。
所以,总结一下我的答案,这是已知解决方案的已知问题,其中没有一个是完全令人满意的(因为它太难了)。选择你的毒药。
回答第二部分(我的想法)你的问题:
如链接问题中所述,您可以在数据库中为自定义字段实现Entity-Attribute-Value,然后添加一个额外的表来保存每个实体的合法值。然后,EAV表的属性/值是属性值表中的外键。
例如,
CREATE TABLE `attribute_value` ( -- enumerations go in this table
`attribute` varchar(30),
`value` varchar(30),
PRIMARY KEY (`attribute`, `value`)
);
CREATE TABLE `eav` ( -- now the values of attributes are restricted
`entityid` int,
`attribute` varchar(30),
`value` varchar(30),
PRIMARY KEY (`entityid`, `attribute`),
FOREIGN KEY (`attribute`, `value`) REFERENCES `attribute_value`(`attribute`, `value`)
);
当然,这个解决方案并不完美或完整 - 它只能说明这个想法。例如,它使用varchars,并且缺少type
列。另外,谁来决定每个属性的可能值是什么?这些可以随时由用户更改吗?
答案 1 :(得分:2)
我正在为客户做类似的事情。我创建了一个JSON FieldType,它包含一个复杂对象的整个JSON流和一个包含我的C#模型类的FQTN(FullQualifiedTypeName)的String。
通过使用自定义的新建,编辑和显示表单,我们确保我们的自定义对象以正确的方式呈现,以获得最佳用户体验。
为了将字段从复杂的C#模型提升到SharePoint列表,我们构建了类似Microsoft在InfoPath中所做的事情。用户可以从Complex C#类型中选择Properties或MetaData,它将自动提升到托管SharePoint列表。
JSON的一大优势是,它比XML更小,更易于在Web世界中使用。 (JavaScript的...)
答案 2 :(得分:2)
当您让用户创建数据模型时,我建议您查看文档数据库或“NoSQL”,因为您只需要存储无模式数据结构。
此外,sharePoint以您提到的方式存储元数据(10列用于文本,5列用于日期等)
也就是说,在我当前的项目中(锁定在SharePoint中,所以Framework 3.5 + SQL Server以及随后的所有约束)我们使用了类似于下面的结构:
Form
Id
Attribute (or Field)
Name
Type (enum) Text, List, Dates, Formulas etc
Hidden (bool)
Mandatory
DefaultValue
Options (for lists)
Readonly
Mask (for SSN etc)
Length (for text fields)
Order
Metadata
FormId
AttributeId
Text (the value for everything but dates)
Date (the value for dates)
我们的公式使用诸如Increment:INC([attribute1][attribute2], 6)
之类的函数,这将为表单的属性1和属性2的组合值的第999个实例生成类似于000999的内容,它存储为:
AttributeIncrementFormula
AtributeId
Counter
Token
其他'公式'(也称为任何非平凡的)(如条形码)存储为单个元数据值。在实际实现中,我们会这样:
var form = formRepository.GetById(1);
form.Metadata["firstname"].Value
上面的值是一个只读属性,它决定我们是否应该从Text或Date获取值,以及是否需要一些额外的转换。请注意,此处的数据库仅仅是一个存储,我们在应用程序中保留了所有域复杂性。
我们也让客户决定哪个属性是表单标题,例如,如果firstname
是表单标题,他们将设置一个内存参数,它跨越整个应用程序,就像{{{ 1}}。
我希望这能让您对类似场景的制作方法有所了解。
答案 3 :(得分:2)
这真的是一个评论而不是一个答案,但我需要更多的空间而不是SO允许评论,所以这里'tis:
我认为您的UserConfiguration表方法很好,并建议只抽取设计中的“类型”和“值”部分:
由于您的应用程序需要验证用户输入,因此“类型”的每个概念都将具有相关的评估逻辑。显然,您可以将更多内容抽象为数据,这样可以更轻松地保持代码较小。枚举列表是一个很好的开始,但如果你的“验证器”逻辑可以扩展到处理文本字符串和布尔逻辑表达式的模式匹配(例如描述/强制对输入值的约束),那么你可以表达几乎任何“类型”您的应用程序可能需要根据(相对)简单的“原子”处理的输入,您可以自然地映射到数据库表。
存储用户指定的值时,可以将“原始”数据(例如,以JSON格式)和外键存储到关联的“类型”中,也可以添加指定的查找/缓存系统系统遇到的每个新值的整数(例如,“新颖性”可以通过检查“原始”数据的散列来检查)。如果您期望大量数据重复(后者当然是多选菜单),后一种方法显然会更好地扩展。