祝大家新年快乐!我刚刚开始为运行工具招聘业务的客户进行ASP.NET MVC 5应用程序数据建模。该解决方案的一部分涉及构建管理员(后端)功能,管理员用户可以通过该功能创建/编辑自定义属性或从特定工具组附加到每个工具的工具元数据。我正在研究一种概念,即应用程序在运行时不应该知道元数据模式是什么。所以我从这里开始:
asp.net-mvc-5 - EntityFramework 6-处理用户定义的属性-LMLPHP
是的,我知道... 另一个EAV噩梦!我知道,如果数据正确归一化并且创建了相关索引,那么它应该不会太差。但老实说,我没有其他选择。因此,例如:
博世无绳电钻

  • 工具组:钻
  • 品牌:Bosch(ListItem-从MetaAttributeListOption表中预填充)
  • 类型:无绳(listItem-从MetaAttributeListOption表中预填充)
  • 无 key 卡盘:是( bool )
  • 电压:14.4伏(文本)
  • ...

  • 现在,这些属性将用于3个目的:
  • 在前端显示为“规范”
  • 用于过滤前端
  • 上的工具
  • (可能)在报表中用于确定“热门品牌”(例如)

  • 因此,我想为此使用RDBMS(SQL Server)。我知道一种流行的方法是使用一些NoSQL解决方案,但是老实说,我没有太多的实践经验可以将它与MSSQL结合使用。我可以将Values表组合到一个表中,其中每个数据类型值都在其自己的列中,但是这将给我留下很多与之抗衡的空值。
    因此,如果您能帮助我,我会遇到以下问题:
  • 此模型是否可以根据我的要求工作?我不确定我是否正确设计了MetaAttributeListOption表的关系。
  • 此EAV方法是否有替代方法?
  • 假设我上面的模型(或其派生模型)是我唯一的选择,我将如何使用Entity Framework 6实现此模型?对于管理员后端中的ASP View Pages,我想我需要某种HTML Helper来确定要呈现的正确编辑器,然后相应地进行填充。

  • 我将非常感谢StackOverflow社区对此提供的任何帮助。如果您需要更多信息,请告诉我,如果您认为它离题,请不要关闭此信息,因为我认为我的问题与编程有关。谢谢!

    编辑:
    我现在开始以此奖励自己的200积分... 100在问题1和2上为我提供帮助/建议,在问题3上获得100积分。谢谢

    最佳答案

  • 问题的模型看起来可行,并且关系配置正确,不同之处在于,如果有很多重复项,则可以创建冗余的OptionLabel。但是,我会做出一些更改和非规范化的折衷。 (请参阅#3)
  • 考虑到您的过滤和报告要求,以及与MSSQL的相对舒适性,我认为使用RDBMS是最好的选择
  • 我已经看到了下面显示的方法在其他一些开发人员的API中使用的方法,这似乎是一个很好的折衷方案,但标准化程度较差,但是使数据模型更简单,并且查询值更加灵活
  • 我添加了MetaAttributeList,以允许一个列表应用于多个MetaAttributes。在此模型中, bool 值将表示为Yes/No ListOption。
  • 问题的模型将要求搜索值检查3个表中的一个(表),并且必须始终事先知道适用的MetaAttribute
  • 默认情况下,使用EF Code First的问题模型具有多个CASCADE路径的问题,这将需要使用FluentApi(虽然不多,但可能不方便跟踪)
  • 此方法(可选?)要求强制执行有效的ListOption条目,而不是使用数据库
  • 进行编码
  • 显示不同类型的值不需要任何额外的工作即可正确呈现
  • 管理界面将需要检查MetaAttribute.ListOption以确定是显示TextBox还是ListItem(如果ListItemOptions为Yes/No,则可能需要复选框)
  • 您可能想为工具组添加另一个表,以缩小提供给用户
  • 的元属性的范围

    注意:由于未指定EF方法和语言,因此我使用EF Code First和VB.Net。 IMO迁移和向EF7的更轻松过渡是使用Code First的充分理由。我更喜欢VB.Net的可读性,但是如果需要的话,我会很乐意更改为C#(或使用this转换器)。

    Imports System.ComponentModel.DataAnnotations
    Namespace Models
        'I didn't bother specifying string lengths with <StringLength(#)>
        Public Class HireTool
            Public Property Id As Integer
            '... other properties
    
            'Navigation Properties
            Public Overridable Property HireToolMetaAttributes As ICollection(Of HireToolMetaAttribute)
        End Class
        Public Class MetaAttribute
            Public Enum MetaAttributeTypeEnum
                Text = 1
                ListItem = 2
            End Enum
            Public Property Id As Integer
            Public Property Code As String
            Public Property Label As String
            Public Property Type As MetaAttributeTypeEnum
            Public Property Required As Boolean
            Public Property Position As Integer
            'Navigation Properties
            Public Overridable Property List As MetaAttributeList
        End Class
        Public Class MetaAttributeList
            Public Property ID As Integer
            Public Property Name As String
            'Navigation Properties
            <Required>
            Public Property ListOptions As ICollection(Of MetaAttributeListOption)
        End Class
        Public Class MetaAttributeListOption
            Public Property Id As Integer
            Public Property OptionLabel As String
        End Class
        Public Class HireToolMetaAttribute
            Public Property Id As Integer
            <Schema.Index> <StringLength(1000)>
            Public Property Value As String
            <Required>
            Public Overridable Property HireTool As HireTool
            <Required>
            Public Overridable Property MetaAttribute As MetaAttribute
        End Class
    End Namespace
    

    编辑:这是生成的SQL:

    CREATE TABLE [dbo].[MetaAttributeLists] (
        [ID]   INT            IDENTITY (1, 1) NOT NULL,
        [Name] NVARCHAR (MAX) NULL,
        CONSTRAINT [PK_dbo.MetaAttributeLists] PRIMARY KEY CLUSTERED ([ID] ASC)
    );
    CREATE TABLE [dbo].[HireTools] (
        [Id] INT IDENTITY (1, 1) NOT NULL,
        CONSTRAINT [PK_dbo.HireTools] PRIMARY KEY CLUSTERED ([Id] ASC)
    );
    CREATE TABLE [dbo].[MetaAttributeListOptions] (
        [Id]                   INT            IDENTITY (1, 1) NOT NULL,
        [OptionLabel]          NVARCHAR (MAX) NULL,
        [MetaAttributeList_ID] INT            NULL,
        CONSTRAINT [PK_dbo.MetaAttributeListOptions] PRIMARY KEY CLUSTERED ([Id] ASC),
        CONSTRAINT [FK_dbo.MetaAttributeListOptions_dbo.MetaAttributeLists_MetaAttributeList_ID] FOREIGN KEY ([MetaAttributeList_ID]) REFERENCES [dbo].[MetaAttributeLists] ([ID])
    );
    CREATE TABLE [dbo].[MetaAttributes] (
        [Id]       INT            IDENTITY (1, 1) NOT NULL,
        [Code]     NVARCHAR (MAX) NULL,
        [Label]    NVARCHAR (MAX) NULL,
        [Type]     INT            NOT NULL,
        [Required] BIT            NOT NULL,
        [Position] INT            NOT NULL,
        [List_ID]  INT            NULL,
        CONSTRAINT [PK_dbo.MetaAttributes] PRIMARY KEY CLUSTERED ([Id] ASC),
        CONSTRAINT [FK_dbo.MetaAttributes_dbo.MetaAttributeLists_List_ID] FOREIGN KEY ([List_ID]) REFERENCES [dbo].[MetaAttributeLists] ([ID])
    );
    CREATE TABLE [dbo].[HireToolMetaAttributes] (
        [Id]               INT             IDENTITY (1, 1) NOT NULL,
        [Value]            NVARCHAR (1000) NULL,
        [HireTool_Id]      INT             NOT NULL,
        [MetaAttribute_Id] INT             NOT NULL,
        CONSTRAINT [PK_dbo.HireToolMetaAttributes] PRIMARY KEY CLUSTERED ([Id] ASC),
        CONSTRAINT [FK_dbo.HireToolMetaAttributes_dbo.HireTools_HireTool_Id] FOREIGN KEY ([HireTool_Id]) REFERENCES [dbo].[HireTools] ([Id]) ON DELETE CASCADE,
        CONSTRAINT [FK_dbo.HireToolMetaAttributes_dbo.MetaAttributes_MetaAttribute_Id] FOREIGN KEY ([MetaAttribute_Id]) REFERENCES [dbo].[MetaAttributes] ([Id]) ON DELETE CASCADE
    );
    GO
    CREATE NONCLUSTERED INDEX [IX_Value]
        ON [dbo].[HireToolMetaAttributes]([Value] ASC);
    GO
    CREATE NONCLUSTERED INDEX [IX_HireTool_Id]
        ON [dbo].[HireToolMetaAttributes]([HireTool_Id] ASC);
    GO
    CREATE NONCLUSTERED INDEX [IX_MetaAttribute_Id]
        ON [dbo].[HireToolMetaAttributes]([MetaAttribute_Id] ASC);
    GO
    CREATE NONCLUSTERED INDEX [IX_MetaAttributeList_ID]
        ON [dbo].[MetaAttributeListOptions]([MetaAttributeList_ID] ASC);
    GO
    CREATE NONCLUSTERED INDEX [IX_List_ID]
        ON [dbo].[MetaAttributes]([List_ID] ASC);
    

    10-08 13:41
    查看更多