【问题标题】:SQL Join tables on different column types不同列类型的 SQL 连接表
【发布时间】:2018-07-22 12:32:05
【问题描述】:

我有两张桌子:

dbo.Dashboards
Id (int PK)  Title(nvarchar)  WidgetIds(nvarchar)
1            Test             [1,2]

dbo.Widgets
Id (int PK)  Details(nvarchar)
1            {'text': 'some data'}
2            {'text': 'test'}

预期输出:

Dashboard.Id     Dashboard.Title     Widget.Id     Widget.Details
1                Test                1             {'text': 'some data'}
1                Test                2             {'text': 'test'}

我想通过使用 Entity Framework 来获得带有指定小部件的仪表板。 我的第一个解决方案是获取dbo.Dashboards,然后获取dbo.Widgets。之后我可以将它合并到后端,但这不是最佳实践。

是否有任何选项可以获取带有指定小部件列表的仪表板? 函数 Include() 不起作用,因为表之间没有 FK 关系。

【问题讨论】:

  • 另外请添加所需的输出
  • 看起来您正在表中存储一些 Json 编码数据。我想这是一个现有的数据库,你不能改变它——你能确认一下吗?如果是,WidgetIds 列对于空列表(例如 null[])和单个项目列表(例如 [1])包含什么?
  • 这是一个现有的数据库,但如果我有严重的原因,我有机会更改它。 WidgetIds 对于空列表包含空数组[],对于单个项目,它包含具有一个元素的数组,例如。 [1]。也就是说,该列包含JSON,我们可以使用SQL函数OPENJSON()轻松打开它。

标签: sql entity-framework foreign-keys left-join entity-framework-core


【解决方案1】:

解决方案 1:

您需要重组 dbo.dashboards 表。将 dbo.dashboards 的列布局更改为 Auto_Generated_ID、Unique_Identifier(PK)、标题、WidgetIds

我知道上述列重组的方式很糟糕。但这仍然适用于您的情况。

重新设计后,您可以使用 dbo.dashboards 和 dbo.widgets 之间的连接来有效地检索它。

解决方案 2:

以下标准化表格适用于您的情况

dbo.dashboard

id、标题(列)

dbo.dashboard_widget

id、dashboard_id、widget_id(列)

dbo.widgets

id、详细信息(列)

查询:

选择 d.id、d.title、dw.widget_ids、w。来自 dbo.dashboard d INNER JOIN dbo.dashboard_widget dw ON d.id = dw.dashboard_id INNER JOIN dbo.widgets w ON dw.widget_id = w.id where d.id = >

的详细信息

【讨论】:

    【解决方案2】:

    在我看来,DashboardsWidgets 之间存在多对多关系:每个 Dashboard 有零个或多个 Widgets,每个 Widget 被零个或多个 @987654328 使用@。

    在适当的数据库中,您将有一个单独的junction table。显然您选择不使用此模式,而是创建一个字符串,其中包含“仪表板”所具有的小部件的文本表示。

    如果您打算创建一个严肃的应用程序,我强烈建议您 在多对多关系中使用标准模式

    如果您不这样做,您的所有查询都会变得更加困难。想象一下,如果您想删除一个 Widget,您会遇到什么问题。您必须检查每个仪表板的文本表示,以检查您要删除的小部件是否在某处使用并更改它。

    如果你想根据Entity Framework Code-First Conventions配置你的多对多关系,你会得到这样的:

    class Dashboard
    {
         public int Id {get; set;}
         public string Title {get; set;}
    
         // every Dashboard has zero or more Widgets
         public virtual ICollection<Widget> Widgets {get; set;}
    
         ... // other properties
    }
    
    class Widget
    {
         public int Id {get; set;}
    
         // every Widget is used in zero or more Dashboards
         public virtual ICollection<Dashboard> Dashboards{get; set;}
    
         ... // other widget properties
    }
    
    class MyDbContext : DbContext
    {
        public DbSet<Dashboard> Dashboards {get; set;}
        public DbSet<Widget> Widgets {get; set;}
    }
    

    因为您遵守约定,所以实体框架需要知道的所有内容才能了解您想要在仪表板和小部件之间配置多对多关系。 Entity Framework 将为您创建联结表。每当您将小部件添加到仪表板时,它都会自动更新此表。每当您想要获取带有小部件的仪表板或带有使用它们的仪表板的小部件时,它也会创建正确的连接。

    您的查询将相当简单:

    var DashBoardsWithTheirWidgets = myDbcontext.Dashboards
    
        // I only want to see the super dashboards
        .Where(dashboard => dashboard.Type = DashboardType.Super)
    
        .Select(dashboard => new
        {
            // Select only the properties you plan to use:
            Id = dashboard.Id,
            Title = dashboard.Title,
    
            // select only the Widgets you plan to use:
            Widgets = dashboard.Widgets
                .Where(widget => widget.Price > 100.00)
                .Select(widget => new
                {
                     // again select only the properties you plan to use
                     Name = widget.Name,
                     Price = widget.Price,
                })
                .ToList();
        });
    

    如果你遵守约定,看看有多容易?

    如果你真的想要使用外键的晦涩方法,你需要一个函数来从 widgetIds 中删除方括号和逗号,将字符串拆分为子字符串,将它们解析为数字,然后进行连接。

    但在您计划继续这条道路之前,请先试验一下如何添加小部件和仪表板。如何将小部件添加到仪表板,如何删除小部件。我认为将数据库改造成适当格式所需的时间远少于实现这些功能所需的时间

    【讨论】:

    • 像往常一样,您将 EF6 与 EF Core 混合使用。 EF Core 不支持这种方式的多对多关系。因此,虽然总的来说您是对的,但在尝试回答 EF Core 相关问题之前,值得阅读 EF Core 概念。
    • 也许,但其中一个标签清楚地表明了实体框架。看到他的外键设计方式,我认为提问者对数据库并不熟悉,仍在决定如何做的阶段,其中一种可能性是实体框架。除了使用这两种方法获得答案之外,还有什么其他理由同时使用这两个标签?
    • EF Core 取代了 EF 标签(毕竟,它的名称中包含实体框架)。我的意思是在建议具体设计或示例时,将 EF Core 考虑在内(包括链接)。在 EFC 中更好地支持一对一、备用键等某些功能,例如具有隐式连接表的多对多功能尚不支持等。
    猜你喜欢
    • 1970-01-01
    • 2019-12-18
    • 1970-01-01
    • 2015-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-09
    • 2013-02-05
    相关资源
    最近更新 更多