许多一对多与实体框架和MVC与排序关系 [英] Many-to-many relationship with Entity Framework and MVC with ordering

查看:107
本文介绍了许多一对多与实体框架和MVC与排序关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用code首先与POCO实体框架4以创建一个多一对多的关系。连接表是正确创建两个实体联系起来。不过,我需要在JOIN表中的附加列创建的关系进行排序。任何方式存档吗?如何在POCO的对象必须进行修改,以包括在JOIN表的附加索引列允许排序?这甚至可能与code首先?如果不是这样,我应该如何进行?

I am using Code First with POCO with Entity Framework 4 to create a many-to-many relationship. The JOIN table is correctly created to link the two entities. However, I need an additional column in the JOIN table to create an ordering in the relationship. Any way to archive this? How do the POCO objects have to be modified to include the additional index column in the JOIN table to allow the ordering? Is this even possible with Code First? If not, how should I proceed?

public class Product
{
    public Guid ID { get; set; }
    public virtual IList<Navigation> Navigations { get; set; }
}

public class Navigation
{
    public Guid ID { get; set; }
    public virtual IList<Product> Products { get; set; }
}

与下列的表是自动创建的,有我想要的顺序附加列:

A table with the following columns is automatically created, there I want an additional column for the ordering:

NavigationProducts
    Navigation_ID
    Product_ID

我可以手动创建附加列,但这样会破坏自动创建表的时候,架构更改。

I could manually create the additional column, but this would break the automatic creation of the tables when the schema changes.

推荐答案

我刚刚做同样的事情。这是我想到的第一个解决方案,我跑了快项目原型吧。它的工作原理,但我几乎没有花费任何时间就可以了,这样的东西告诉我,整个事情可以更有效的,给予更多的想到。但它是相当灵活。

I've just had to do something similar. It's the first solution I thought of, and I ran a quick project to prototype it. It works, although I have barely spent any time on it, so something tells me the whole thing could be made more efficient, given more thought. It is quite flexible however.

我用这两个术语网页和Widget在此解决方案,并澄清,我期待以下行为:

I've used the two terms Webpage and Widget in this solution, and to clarify, I'm expecting the following behaviour:

  • 在一个网页可以有分配给它的许多小部件,而这些部件必须订购/订单能。
  • 同时一个Widget可以分配给许多不同的网页。
  • 的小部件必须保持不同排序为它们附加到每个不同的网页。

我用4实体在这个例子中,虽然使用1实体作为症结此溶液铰链周围。这种实体被映射到它自己的表,并提供2个连接表脱落了它 - 而这些转至表2实体我本来想为许多一对多的关系

I've used 4 Entities in this example, although this solution hinges around using 1 Entity as the crux. This Entity gets mapped to it's own table and provides 2 join tables coming off it -- and these go to the tables for the 2 Entities that I originally wanted the Many-To-Many relationship for.

的实体是如下:

IndexedWebpageWidget:这是最重要的实体。这两个具体的实体下面有这个实体一个多到一的关系。

IndexedWebpageWidget: This is the important Entity. Both Concrete Entities below have a Many-To-One relationship with this Entity.

的BaseUnit:作为抽象基类的页面控件的 - (包含ID,标题和内容属性)

BaseUnit: Abstract base class for Webpage and Widget - (contains Id, Title and Content properties)

网页:混凝土的的BaseUnit 的子类,包含一个额外的属性(一个列表的 IndexedWebpageWidget 的)

Webpage: Concrete BaseUnit subclass, containing one extra property (a List of IndexedWebpageWidget).

小工具:同网页,还包含一个额外的属性(也是一个List IndexedWebpageWidget 的)

Widget: Same as webpage, also containing one extra property (also a List of IndexedWebpageWidget).

的BaseUnit:

public abstract class BaseUnit
    {
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [Required, MaxLength(300)]
        public string Title { get; set; }

        [Required, AllowHtml]
        public string Content { get; set; }
    }

窗口小部件&放大器;网页:

public class Widget : BaseUnit
{
    [InverseProperty("Widget")]
    public virtual List<IndexedWebpageWidget> Webpages { get; set; }
}

public class Webpage : BaseUnit
{
    [InverseProperty("Webpage")]
    public virtual List<IndexedWebpageWidget> Widgets { get; set; }
}

IndexedWebpageWidget:

public class IndexedWebpageWidget
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public int Order { get; set; }

    [Required]
    [InverseProperty("Widgets")]
    public virtual Webpage Webpage { get; set; }

    [Required]
    [InverseProperty("Webpages")]
    public virtual Widget Widget { get; set; }
}

在[InverseProperty]属性这里告诉Entity Framework的这端是哪个。这可能是不需要作为知道其中有一对许多最终是主要的。该主键的外键。

The [InverseProperty] attributes here are to tell Entity Framework which ends are which. This is probably not needed as knows which end of a One-To-Many is the principal. the primary keys are the foreign keys.

我创建了一个快速的DbContext和DBInitialiser,并用它来填充数据库。 这些看起来是这样的:

I created a quick DbContext, and a DBInitialiser, and used this to populate the DB. These look like this:

public class WebWidgetTestContext : DbContext
    {
        public DbSet<Webpage> Webpages { get; set; }
        public DbSet<Widget> Widgets { get; set; }
        public DbSet<IndexedWebpageWidget> WebpageWidgets { get; set; }
    }

    public class WebWidgetInitialiser : DropCreateDatabaseIfModelChanges<WebWidgetTestContext>
    {
        protected override void Seed(WebWidgetTestContext context)
        {
            //
            // create 3 pages
            //

            var webpageA = new Webpage
            {
                Title = "Webpage A",
                Content = "Content for Webpage A",
                Widgets = new List<IndexedWebpageWidget>()
            };

            var webpageB = new Webpage
            {
                Title = "Webpage B",
                Content = "Content for Webpage B",
                Widgets = new List<IndexedWebpageWidget>()
            };

            var webpageC = new Webpage
            {
                Title = "Webpage C",
                Content = "Content for Webpage C",
                Widgets = new List<IndexedWebpageWidget>()
            };


            //
            // create 3 widgets
            //

            var widget1 = new Widget
            {
                Title = "Widget 1",
                Content = "Content for Widget 1",
                Webpages = new List<IndexedWebpageWidget>()
            };

            var widget2 = new Widget
            {
                Title = "Widget 2",
                Content = "Content for Widget 2",
                Webpages = new List<IndexedWebpageWidget>()
            };

            var widget3 = new Widget
            {
                Title = "Widget 3",
                Content = "Content for Widget 3",
                Webpages = new List<IndexedWebpageWidget>()
            };


            // now match them up

            var map1 = new IndexedWebpageWidget
            {
                Webpage = webpageA,
                Widget = widget1,
                Order = 1
            };

            var map2 = new IndexedWebpageWidget
            {
                Webpage = webpageA,
                Widget = widget2,
                Order = 2
            };

            var map3 = new IndexedWebpageWidget
            {
                Webpage = webpageB,
                Widget = widget1,
                Order = 1
            };

            var map4 = new IndexedWebpageWidget
            {
                Webpage = webpageB,
                Widget = widget3,
                Order = 3
            };

            var map5 = new IndexedWebpageWidget
            {
                Webpage = webpageC,
                Widget = widget2,
                Order = 2
            };

            var map6 = new IndexedWebpageWidget
            {
                Webpage = webpageC,
                Widget = widget3,
                Order = 1
            };

            // add
            context.WebpageWidgets.Add(map1);
            context.WebpageWidgets.Add(map2);
            context.WebpageWidgets.Add(map3);
            context.WebpageWidgets.Add(map4);
            context.WebpageWidgets.Add(map5);
            context.WebpageWidgets.Add(map6);

            // save
            context.SaveChanges();

        }
    }

_

您可以看到,我已经加了3 DBSets上下文。我这样做,所以很容易对我来说,种子在初始化器数据库。

You can see that I've added 3 DBSets to the context. I did this so it was easy for me to seed the database in the Initialiser.

需要注意的是map5和MAP6分配不同的顺序,以小部件的网页ç...

Note that map5 and map6 assign different ordering to the widgets for Webpage C...

另外值得一提的是,实体框架创建只有3桌 - dbo.IndexedWebpageWidgets dbo.Webpages dbo.Widgets 。该表IndexedWebpageWidgets的行为就像一个单一的连接表中,并添加订单场。

It's also worth noting that Entity Framework creates only 3 tables - dbo.IndexedWebpageWidgets, dbo.Webpages, and dbo.Widgets. The table for IndexedWebpageWidgets acts exactly like a single join table, with an added order field.

_

最后,有一个快速查看我修改了家居控制器:

Finally, to have a quick viewing I modified my home controller:

public class HomeController : Controller
{
    private WebWidgetTestContext db = new WebWidgetTestContext();

    public ActionResult Index()
    {
        var model = db.Webpages.ToList();

        return View(model);
    }
}

在我看来:

@model List<WebpageWidgetTest.Models.Webpage>
@{
    ViewBag.Title = "Home Page";
}
<h2>@ViewBag.Message</h2>
<div>
    @{
        foreach (var webpage in Model)
        {
        <div>
            <h4>@webpage.Title</h4>
            <p>@webpage.Content</p>
            <p>Applicable Widgets:</p>
            @foreach (var widget in webpage.Widgets.OrderBy(w => w.Order))
            {
                <div>
                    <h5>@widget.Widget.Title (@widget.Order)</h5>
                    <p>@widget.Widget.Content</p>
                </div>
            }
        </div><hr /><br /><br />
        }
    }
</div>

在剃刀code以上的视图模型是所有网页的列表。通过他们,我环路和写出来的标量属性。那么对于小工具属性,我在循环每个IndexedWebpageWidget和写出来的部件,为了。交换的分贝的顺序属性的值将导致他们出现在不同的订单。

In the Razor code above the ViewModel is a list of all the webpages. I loop through them and write out the scalar properties. Then for each IndexedWebpageWidget in the Widgets property, I loop and write out the widgets, in order. Swapping the value of the order property in the db will cause them to appear in different orders.

-

这主要产生以下HTML:

This basically yields the following HTML:

Webpage A

Content for Webpage A

Applicable Widgets:

Widget 1 (1)

Content for Widget 1

Widget 2 (2)

Content for Widget 2



Webpage B

Content for Webpage B

Applicable Widgets:

Widget 1 (1)

Content for Widget 1

Widget 3 (3)

Content for Widget 3



Webpage C

Content for Webpage C

Applicable Widgets:

Widget 3 (1)

Content for Widget 3

Widget 2 (2)

Content for Widget 2

-

您可以在网页C,它的Widget 3自带小工具2之前,基于它看到的顺序属性(其旁边显示括号内每个插件的标题)...交换的顺序一个部件对一个网页都不会影响它的订货另一个网页。 因此,所有的要求都已经达到。

You can see in Webpage C that Widget 3 comes before widget 2, based on it's order property (which is shown next to each widget's title in brackets)... Swapping the order for one widget against a webpage will not affect it's ordering for another webpage. Therefore all requirements have been achieved.

这种方法的唯一真正的缺点是,你有一个额外的实体。这实际上就派上用场了,虽然对2个对象是捆绑在一起的穿越。我不知道的另一种方式,可以这样做。的关系,每一方需要映射,这样我就可以所有的导航属性只是添加到了的BaseUnit类。

The only real downside of this approach is that you have one extra entity. This actually comes in handy though for traversing between the 2 objects it ties together. I'm not sure of another way that this could be done. Each side of a relationship needs to be mapped, so I could just add all the navigation properties into a the BaseUnit class.

_

无论如何,我希望这会有所帮助。

Anyway, I hope this helps.

干杯,

这篇关于许多一对多与实体框架和MVC与排序关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆