多对多关系,联结表无法识别

时间:2022-10-05 11:48:28

I would like to set up a many to many relationship in ASP.NET MVC4. The goal is to extend the default UserProfile class with a list of Timeline objects, which belong to the user. A Timeline could be shared by multiple users, so the Timeline class should have an list of UserProfile objects aswell.

我想在ASP.NET MVC4中建立多对多的关系。目标是使用属于用户的Timeline对象列表扩展默认UserProfile类。时间轴可以由多个用户共享,因此Timeline类应该具有UserProfile对象的列表。

Timeline class:

时间线课程:

namespace MvcApplication1.Models
{
    public class Timeline
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Color { get; set; }
        public List<UserProfile> Users { get; set; }
    }

    public class TimelineContext : DbContext
    {
        public DbSet<Timeline> Timelines { get; set; }
        public DbSet<UserProfile> UserProfiles { get; set; }

        // Added the following because I saw it on:
        // http://www.codeproject.com/Tips/548945/Generating-Many-to-Many-Relation-in-MVC4-using-Ent
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<Timeline>()
                .HasMany(c => c.Users)
                .WithMany(s => s.Timelines)
                .Map(mc =>
                {
                    mc.ToTable("TimelineOwners");
                    mc.MapLeftKey("TimelineId");
                    mc.MapRightKey("UserId");
                });
        }
    }
}

UserProfile class (default class with an added property):

UserProfile类(具有添加属性的默认类):

public class UsersContext : DbContext
{
    public UsersContext()
        : base("DefaultConnection")
    {
    }

    public DbSet<UserProfile> UserProfiles { get; set; }
    public DbSet<Timeline> Timelines { get; set; }

    // Added the following because I saw it on:
    // http://www.codeproject.com/Tips/548945/Generating-Many-to-Many-Relation-in-MVC4-using-Ent
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<UserProfile>()
            .HasMany(c => c.Timelines)
            .WithMany(s => s.Users)
            .Map (mc =>
                {
                   mc.ToTable("TimelineOwners");
                   mc.MapLeftKey("UserId");
                   mc.MapRightKey("TimelineId");
               });
    }
}

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }

    public List<Timeline> Timelines { get; set; }
}

I have a connection table with foreign keys:

我有一个带外键的连接表:

多对多关系,联结表无法识别

多对多关系,联结表无法识别

多对多关系,联结表无法识别

When creating an instance of Timeline, the Users list is null:

创建时间轴实例时,“用户”列表为空:

Timeline timeline = db.Timelines.Find(id); // timeline.Users = null

Can somebody please enlighten me, how should I set this up working?

有人可以赐教,我该如何设置呢?

I'm totally new to ASP.NET MVC4.

我是ASP.NET MVC4的新手。

Edit 1: I understand I should not extend UserProfile but create another class to store users. Once the many-to-many relationship works, I will refactor and go into that direction. But first I would like to know why is it not working.

编辑1:我知道我不应该扩展UserProfile,而是创建另一个类来存储用户。一旦多对多关系奏效,我将重构并朝着这个方向前进。但首先我想知道它为什么不起作用。

Edit 2: The double context also caused problems, two databases were created for the two contexts and the pure join table was empty in one of them.

编辑2:双上下文也导致了问题,为两个上下文创建了两个数据库,其中一个纯连接表为空。

2 个解决方案

#1


1  

I suggest that you work through this article about the options how you can load navigation properties with Entity Framework. This is very basic knowledge which is important for every kind of relationship, not only many-to-many relationships.

我建议您通过本文讨论如何使用Entity Framework加载导航属性的选项。这是非常基本的知识,对每种关系都很重要,而不仅仅是多对多的关系。

Looking at that article you will find then that this line...

看那篇文章,你会发现这一行......

Timeline timeline = db.Timelines.Find(id);

...does not load any related entities. So, it's expected that timeline.Users is null, even if the entities are related in the database.

...不加载任何相关实体。因此,即使实体在数据库中相关,期望timeline.Users为null。

If you want to load the Users you can use eager loading:

如果要加载用户,可以使用预先加载:

Timeline timeline = db.Timelines.Include(t => t.Users)
    .SingleOrDefault(t => t.Id == id);

This is a single database query. Or to enable lazy loading you have to mark your navigation properties as virtual:

这是一个单一的数据库查询。或者要启用延迟加载,您必须将导航属性标记为虚拟:

public virtual List<UserProfile> Users { get; set; }

//...

public virtual List<Timeline> Timelines { get; set; }

You can then use your original code:

然后,您可以使用原始代码:

Timeline timeline = db.Timelines.Find(id); // first query
var users = timeline.Users;                // second query

This will run two separate queries. The second is performed as soon as you access the navigation property for the first time.

这将运行两个单独的查询。第一次访问导航属性时会执行第二次操作。

BTW: Is there a reason why you have two context classes - TimelineContext and UsersContext? "Normally" you need only one context.

顺便说一句:你有两个上下文类--TimelineContext和UsersContext? “通常”你只需要一个上下文。

#2


0  

I'm not a fan of messing with the working of the internal userprofile. I would suggest creating your own user class, linking it to the simplemembershipprovider and adding functionality there. At max you'll extend the accountclasses a little to add more fields to register with, but that's about it.

我不喜欢搞乱内部用户配置文件的工作。我建议创建自己的用户类,将其链接到simplemembershipprovider并在那里添加功能。在max,您将稍微扩展一下帐户类以添加更多要注册的字段,但这就是它。

Follow this extremely handy guide to get things working and let me know if you encounter an error.

按照这个非常方便的指南,让事情工作,如果您遇到错误,请告诉我。

#1


1  

I suggest that you work through this article about the options how you can load navigation properties with Entity Framework. This is very basic knowledge which is important for every kind of relationship, not only many-to-many relationships.

我建议您通过本文讨论如何使用Entity Framework加载导航属性的选项。这是非常基本的知识,对每种关系都很重要,而不仅仅是多对多的关系。

Looking at that article you will find then that this line...

看那篇文章,你会发现这一行......

Timeline timeline = db.Timelines.Find(id);

...does not load any related entities. So, it's expected that timeline.Users is null, even if the entities are related in the database.

...不加载任何相关实体。因此,即使实体在数据库中相关,期望timeline.Users为null。

If you want to load the Users you can use eager loading:

如果要加载用户,可以使用预先加载:

Timeline timeline = db.Timelines.Include(t => t.Users)
    .SingleOrDefault(t => t.Id == id);

This is a single database query. Or to enable lazy loading you have to mark your navigation properties as virtual:

这是一个单一的数据库查询。或者要启用延迟加载,您必须将导航属性标记为虚拟:

public virtual List<UserProfile> Users { get; set; }

//...

public virtual List<Timeline> Timelines { get; set; }

You can then use your original code:

然后,您可以使用原始代码:

Timeline timeline = db.Timelines.Find(id); // first query
var users = timeline.Users;                // second query

This will run two separate queries. The second is performed as soon as you access the navigation property for the first time.

这将运行两个单独的查询。第一次访问导航属性时会执行第二次操作。

BTW: Is there a reason why you have two context classes - TimelineContext and UsersContext? "Normally" you need only one context.

顺便说一句:你有两个上下文类--TimelineContext和UsersContext? “通常”你只需要一个上下文。

#2


0  

I'm not a fan of messing with the working of the internal userprofile. I would suggest creating your own user class, linking it to the simplemembershipprovider and adding functionality there. At max you'll extend the accountclasses a little to add more fields to register with, but that's about it.

我不喜欢搞乱内部用户配置文件的工作。我建议创建自己的用户类,将其链接到simplemembershipprovider并在那里添加功能。在max,您将稍微扩展一下帐户类以添加更多要注册的字段,但这就是它。

Follow this extremely handy guide to get things working and let me know if you encounter an error.

按照这个非常方便的指南,让事情工作,如果您遇到错误,请告诉我。