简体   繁体   中英

SQL Join tables on different column types

I have two tables:

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'}

Expected output:

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

I would like to get dashboards with assigned widgets by using Entity Framework. My first solution is to get dbo.Dashboards and then dbo.Widgets . After that I can merge it in a backend, but it is not the best practice.

Is there any option to get Dashboards with assigned Widget list? Function Include() is not working because there isn't FK relationship between tables.

It seems to me that you have a many-to-many relationship between Dashboards and Widgets : Every Dashboard has zero or more Widgets and every Widget is used by zero or more Dashboards .

In a proper database you would have a separate junction table . Apparently you chose not to use this pattern, but create a string that contains a textual representation of the widgets that a 'Dashboard` has.

If you plan to create a serious application I strongly advise you to use the standard pattern in many-to-many relationships

If you don't, all your queries will be more difficult. Imagine the problems you'll experience if you want to delete a Widget. You'd have to check the textual representation of every Dashboard to check if the widget that you want to remove is used somewhere and change it.

If you want to configure your many-to-many relations ship according to the Entity Framework Code-First Conventions , you will have something like this:

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;}
}

Because you stuck to the conventions, this is all that entity framework needs to know to understand that you want to configure a many-to-many relationship between Dashboards and Widgets. Entity Framework will create the junction table for you. It will automatically update this table whenever you add a Widget to a Dashboard. It will also create the proper joins whenever you want to fetch Dashboards with their Widgets, or Widgets with the Dasheboards that use them.

Your query will be fairly simple:

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();
    });

See how easy it is if you stick to the conventions?

If you really want your obscure method of using foreign keys, you need a function to remove the square brackets and the commas from the widgetIds, split the string into sub-strings, Parse them to numbers, and do a join.

But before you plan to continue on this path, experiment on how to add a Widget and a Dashboard. How to add a Widget to a Dashboard, how to remove a Widget. I think the time needed to reform your database into proper format is much less than the time you'll need to implement those functions

Solution 1:

You need to restructure the dbo.dashboards table. Change the column layout of dbo.dashboards to Auto_Generated_ID, Unique_Identifier(PK), Title, WidgetIds

I know the above column restructuring is done in a bad way. But still this will work in your case.

After redesigning it you can use join between dbo.dashboards and dbo.widgets to retrieve it in an efficient way.

Solution 2:

The below-normalized tables will work in your case

dbo.dashboard

id, title (columns)

dbo.dashboard_widget

id, dashboard_id, widget_id (columns)

dbo.widgets

id, details (columns)

Query:

select d.id, d.title, dw.widget_ids, w. details from 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 = << id number >>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM