SQL Server和Entity Framework - 动态列

3
我使用SQL Server和Entity Framework作为ORM。
当前我有一个名为“Product”的表,其中包含所有种类的产品。不同种类的产品具有不同的属性。
例如:
- 所有类型的电视都具有标题、分辨率和对比度等属性 - 而所有汽车类型的产品都具有模型和马力等属性
基于这种情况,我创建了一个名为“Attribute”的表,其中包含产品的所有属性。
现在,要从数据库中获取产品,我必须始终连接所有属性。
要插入产品,我必须逐个插入所有属性作为单独的行。
该应用程序不仅仅是商店或类似的东西。它应该可以在不更改数据库的情况下随时添加/删除某种产品的属性。
但是,我仍然有以下几个问题:
- 这是一种不好的设计吗? - 是否有另一种方法来处理它? - 我的解决方案会显着减慢速度吗?(例如,假设产品有数百个属性,则插入需要几秒钟...)
更新:
问题在于我的应用程序非常复杂。有许多巨大的算法。该软件用于统计目的。
例如,一个问题是:在算法表中,我正在存储哪些属性用于过滤器。例如,管理员想要筛选所有马力小于100的汽车。过滤器是动态的,这意味着我有一个过滤器表,其中存储了过滤器类型(lessThan)和属性(马力)。如何使用建议的方法保持此灵活性(使用“硬编码”列)?

5
是的,这是一个非常糟糕的设计——它被称为“实体属性值(EAV)”并被认为是一种“反模式”——尽量避免使用!请参见五个应该避免的简单数据库设计错误(第三点),了解为什么EAV真的很糟糕,另请参见Bad CaRMa,了解一个EAV系统设计毁掉一家蓬勃发展的公司的真实恐怖故事。 - marc_s
谢谢您的评论,但有时候当似乎没有其他解决方案时,我们不得不使用反模式...或者我错了吗?还有其他方法吗? - sjkm
1
有很多选择:**(1)** 定义一个 BaseProduct 表,包含通用属性,然后创建 CarsTV 表引用基础产品表,并添加额外的属性;或者如果这仍然过于严格:**(2)** 在表上放置基本属性,将任何其他自定义属性存储到 XML 列中 - 这只是我个人使用并取得巨大成功的两种选择 - 我相信还有许多其他选择! - marc_s
谢谢你,marc_s。非常感谢你的建议!问题是我使用复杂的 SQL 计算来处理各种产品。有很多连接需要我“动态”地进行(一次必须连接到“汽车”,一次必须连接到“电视”)。否则,我将不得不为每种产品编写多个 SQL 代码片段...你能帮我想想吗? - sjkm
你是说你正在使用Entity Framework,对吗?EF可以将父子表用作单个实体,例如,你可以在EF中拥有一个“Car”实体,其中它的一些值在“BaseProduct”中,汽车特定的值在“Car”中。同样适用于“TV”。这样,如果你可以将计算从SQL移动到EF中,你可以简单地使用一个很好的对象模型,不必担心JOINs和其他一切... - marc_s
是的,我明白了。你说得很对。问题在于我的应用程序非常复杂。有许多庞大的算法。该软件用于统计目的。例如,一个问题是:在算法表中,我存储了哪些属性用于过滤。假设管理员想要过滤所有马力小于100匹的汽车。过滤器是动态的,这意味着我有一个过滤器表,它存储过滤器类型(lessThan)和属性(horsepowers)。如何使用您的方法(使用“硬编码”列)保持此灵活性? - sjkm
1个回答

1
关于EF设计关系时,有一件事情我认为不是每个人都知道。当您查询某些内容时,EF(至少≤4)想要为该查询创建一个单独的SELECT。这意味着,如果您有实体A,它与实体B(例如Item到Attributes)之间有一对多的关系,则EF将两者连接在一起,因此将为每个A返回所有相关的B行。如果A有许多属性、多个依赖项,甚至更糟糕的是B有许多子依赖项,则返回的表格将非常庞大,因为每个依赖B的行都会复制所有A属性。随着时间的推移,当您的实体模型变得越来越复杂时,这可能会成为真正的性能问题。只有在明确告诉它要急切加载依赖项“include”时,EF才会包括Bs。如果省略了这些包含内容,则您的内容将最初加载得更快,但一旦访问属性,它们将由EF进行延迟加载。这被称为SELECT N+1问题(每个A将需要N次B-lazy查询,这可能是巨大的开销)。虽然这不是直接回答您问题的答案,但在设计表时需要考虑这一点。
请注意,EF支持多种基类策略。一种策略是使用一个公共表,它会自动与子实体连接在一起。另一种策略通常性能更好,但升级难度较大,即使用一个包含所有子类属性超集的表。
更多(过度)概括的数据库设计考虑:
  • 魔鬼在细节中。你可以通过做出好的数据库设计选择来建立整个职业生涯。没有银弹式的数据库模式。
  • EF带有许多限制,这是方便所付出的代价。如果模型适合EF,那么EF相当不错,但请考虑更灵活的替代方案,如NHibernate。有时甚至更喜欢使用带有视图和存储过程的普通数据表。
  • 如果您的模型具有大量小的依赖项(例如对项目表的大量属性),则EF效率不高。它将导致一个庞大的查询和返回表或选择n + 1问题。您可以编写一些棘手的多部分LINQ查询来进行某种程度的补偿,但这很棘手。
  • SQL的优势在于完整性和报告,最适用于相当严格的数据模型。
  • 根据细节,您的模型看起来像是NoSql后端的绝佳候选,例如RavenDb和MongoDb。NoSql非常适用于动态数据模型,并且可以很好地扩展。

谢谢你,holstebroe!请阅读我在上面最后一条评论中对你的建议所表达的担忧。谢谢。 - sjkm
如果您有不仅是自定义元数据而且在实际业务逻辑中使用的属性,那么将该属性提升为更少动态的内容是有意义的。例如,如果“价格”是所有实体共享的属性,则可以为基类专门分配一个属性。总的来说,我认为如何表示属性并没有明确的答案。这取决于对它们的变化可能性、数量(数十万或数百万)以及是否可以共享的分析。 - Holstebroe
请注意,EF支持存储过程和视图。虽然它们都需要维护开销,但它们允许您在设计中拥有更多的自由度。 - Holstebroe
非常感谢。我也认为没有明确的答案。大多数属性都不共享,必须能够引用它们进行特定计算。那么,您认为我的反模式方法最终是可以接受的妥协吗? - sjkm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接