在我们的应用程序中,用户可以创建不同的列表(例如sharepoint),例如用户可以创建汽车列表(名称,型号,品牌)和学生列表(姓名,dob,地址,国籍)等
我们的应用程序应该能够查询列表的不同列,这样我们就不能只序列化每一行并将其保存在一行中。
我应该在运行时为每个新创建的列表创建一个新表吗?如果这是最好的解决方案,那么我认为可能Microsoft SharePoint也会做到这一点?
我应该使用以下架构
Lists (Id, Name)
ListColumns (Id, ListId, Name)
ListRows (Id, ListId)
ListData(RowId, ColumnId, Value)
虽然单行会在列表数据表中创建与列表中的列一样多的行,但这感觉不对。
你有没有处理过这种情况?你是如何在数据库中处理它的?
答案 0 :(得分:3)
你做的是EAV (Entity-Attribute-Value Model)。
对于包含3列和1000个条目的列表:
列表中的1条记录 ListColumns中的3条记录 ListData中的3000个条目和
中的3000个条目这很好。我不是动态创建表的粉丝,因为它可能会弄乱你的数据库,你必须动态地“生成”你的SQL查询。当用户可以在我的数据库中创建/删除/更改表时,我会感到奇怪的感觉!
EAV模型的另一个不错的功能是,您可以轻松地合并两个列表,而无需删除和更改表。
修改:
我认为您需要另一个名为ListRows的表来告诉您哪些ListData记录连续存在!
答案 1 :(得分:2)
我以前经历过这样的事情 - 我不想分享实际的表模式,所以让我们使用一些建议的表结构做一些思考练习:
lists
表,其中包含我所有列表的列表columns
表values
表
rows
表,其中包含所有行的列表,否则很难计算出实际有多少行为了简单起见,我们只需将所有内容都设为字符串(VARCAHR
),然后再进行一些查询:
计算表格中的所有行
SELECT COUNT(*) FROM [rows]
JOIN [lists]
ON [rows].list_id = [Lists].id
WHERE [Lists].name = 'Cars'
嗯,不是太糟糕,相比之下:
SELECT * FROM [Cars]
在表格中插入行
BEGIN TRANSACTION
DECLARE @row_id INT
DECLARE @list_id INT
SELECT @list_id = id FROM [lists] WHERE name = 'Cars'
INSERT INTO [rows] (list_id) VALUES (@list_id)
SELECT @row_id = @@IDENTITY
DECLARE @column_id INT
-- === Need one of these for each column ===
SELECT @column_id = id FROM [columns]
WHERE name = 'Make'
AND list_id = @list_id
INSERT INTO [values] (column_id, row_id, value)
VALUES (@column_id, @row_id, 'Rover')
-- === Need one of these for each column ===
SELECT @column_id = id FROM [columns]
WHERE name = 'Model'
AND list_id = @list_id
INSERT INTO [values] (column_id, row_id, value)
VALUES (@column_id, @row_id, 'Metro')
COMMIT TRANSACTION
嗯,与以下相比,开始有点毛茸茸:
INSERT INTO [Cars] ([Make], [Model}) VALUES ('Rover', 'Metro')
简单查询
我现在厌倦了构建繁琐复杂的SQL语句,所以也许你可以为followng语句提出等效的查询:
SELECT [Model] FROM [Cars] WHRE [Make] = 'Rover'
SELECT [Cars].[Make], [Cars].[Model], [Owners].[Name] FROM [Cars]
JOIN [Owners] ON [Owners].id = [Cars].owner_id
WHERE [Owners].Age > 50
SELECT [Cars].[Make], [Cars].[Model], [Owners].[Name] FROM [Cars]
JOIN [Owners] ON [Owners].id = [Cars].owner_id
JOIN [Addresses] ON [Addresses].id = [Owners].address_id
WHERE [Addresses].City = 'London'
我希望你开始明白这个想法......
简而言之 - 我以前经历过这一点,我可以向您保证,以这种方式在数据库中创建数据库绝对是一件坏事。
如果你需要做任何事情,但是对这些列表进行最基本的查询(我的意思是“我可以将此列表中的所有项目都包括在内吗?”),你应该尝试找一个替代品。
只要每个用户都有自己的数据库,我肯定会推荐CREATE TABLE
方法。即使他们不这样做,我仍然建议你至少考虑一下。
答案 2 :(得分:1)
也许潜在的解决方案是创建列表可能涉及这些实体/列表的CREATE TABLE
语句?
听起来db结构或模式可以在运行时或用户的命令中更改,所以这样的事情可能会有所帮助吗?
正确编码,我们正在处理以下要求:让用户创建新实体。这里没有提到规模。当然,这需要对所有输入进行清理,查询参数化,记录操作等。
下面的否定评论实际上并没有给出任何合理的理由,但会产生一些FUD。我有兴趣解决这个潜在解决方案的任何问题。我们还没有听说过规模,安全性,性能或使用情况(内部局域网与互联网)。
答案 3 :(得分:1)
当用户创建列表时,绝对不应动态创建表。这不是数据库的工作方式。
您的架构是正确的,在我看来,复数也是正确的,但我会移除驼峰案例并将其称为lists
,list_columns
,list_rows
和{{ 1}}。
我会通过跳过list_data
和rows
表来进一步改进您的架构,它们没有用处。只需在每个单元格上附加行/列编号,并保持稀疏:不要打扰在数据库中保留空单元格。您保留了基于行/列查询/排序的功能,您的查询将(可能非常)更快,因为columns
的数量将减少,您将不必疯狂加入链接你的数据回到了它的表格。
这是完整的架构:
list_cells
答案 4 :(得分:0)
听起来您可能已在您的环境中部署了Sharepoint。
考虑将您的应用程序与Sharepoint集成,并将其作为您的数据存储区。当你可以利用它时,无需重新创建你喜欢的所有关于Sharepoint的东西。
需要进行一些配置,但您可以调用SP Web服务来为您提供CRUD列表数据。
Sharepoint 2010还可以通过OData公开列表,这可以很容易地从任何应用程序中使用。