代码优先迁移的外键不应该存在

时间:2017-02-27 03:56:38

标签: c# sql-server entity-framework ef-migrations

我目前有2个模型需要运行迁移到新数据库中,而且我没有得到我期望的结构。如果这是一个简单的答案我很抱歉,我对Code First with Entity Framework相当新。

首先我有一个User个对象。这只需要一个主键UserID,然后填写一些字段。

public class User : CustomDataEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserID { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public DateTime Birthday { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string EmailAddress { get; set; }
    public byte[] Picture { get; set; }
}

然后,我有一个Event对象。这应该有一个EventID作为主键,然后我尝试使用ForeignKey' d HostUser,以及注册该事件的用户列表,存储在RegisteredUsers表中。

public class Event : CustomDataEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int EventID { get; set; }
    [ForeignKey("HostUser")]
    public int HostUserID { get; set; }
    [ForeignKey("RegisteredUsers")]
    public ICollection<int> RegisteredUserIDs { get; set; }
    public virtual User HostUser { get; set; }
    public string Description { get; set; }
    public virtual ICollection<User> RegisteredUsers { get; set; }
}

基于此,我希望有一个包含UserEvent表的数据库结构,在dbo.EventUser表中有一个外键列(对于外键的HostUserID),以及将用户列表映射到事件的查找表(对于RegisteredUsers列表)。

问题在于,当我根据此结构创建迁移时,我会为Up()部分获取以下CreateTable方法。

public override void Up()
    {
        CreateTable(
            "dbo.Event",
            c => new
                {
                    EventID = c.Int(nullable: false, identity: true),
                    HostUserID = c.Int(nullable: false),
                    Description = c.String(nullable: false),
                    NumberOfUsers = c.Int(nullable: false),
                    StartDate = c.DateTime(nullable: false),
                    EndDate = c.DateTime(),
                    CreatedAt = c.DateTimeOffset(precision: 7,
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "ServiceTableColumn",
                                new AnnotationValues(oldValue: null, newValue: "CreatedAt")
                            },
                        }),
                    Deleted = c.Boolean(nullable: false,
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "ServiceTableColumn",
                                new AnnotationValues(oldValue: null, newValue: "Deleted")
                            },
                        }),
                    Id = c.String(
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "ServiceTableColumn",
                                new AnnotationValues(oldValue: null, newValue: "Id")
                            },
                        }),
                    UpdatedAt = c.DateTimeOffset(precision: 7,
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "ServiceTableColumn",
                                new AnnotationValues(oldValue: null, newValue: "UpdatedAt")
                            },
                        }),
                    Version = c.Binary(
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "ServiceTableColumn",
                                new AnnotationValues(oldValue: null, newValue: "Version")
                            },
                        }),
                })
            .PrimaryKey(t => t.EventID)
            .ForeignKey("dbo.User", t => t.HostUserID, cascadeDelete: true)
            .Index(t => t.HostUserID);

        CreateTable(
            "dbo.User",
            c => new
                {
                    UserID = c.Int(nullable: false, identity: true),
                    Username = c.String(nullable: false),
                    Password = c.String(nullable: false),
                    Birthday = c.DateTime(nullable: false),
                    FirstName = c.String(nullable: false),
                    LastName = c.String(nullable: false),
                    EmailAddress = c.String(nullable: false),
                    Picture = c.Binary(),
                    CreatedAt = c.DateTimeOffset(precision: 7,
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "ServiceTableColumn",
                                new AnnotationValues(oldValue: null, newValue: "CreatedAt")
                            },
                        }),
                    Deleted = c.Boolean(nullable: false,
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "ServiceTableColumn",
                                new AnnotationValues(oldValue: null, newValue: "Deleted")
                            },
                        }),
                    Id = c.String(
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "ServiceTableColumn",
                                new AnnotationValues(oldValue: null, newValue: "Id")
                            },
                        }),
                    UpdatedAt = c.DateTimeOffset(precision: 7,
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "ServiceTableColumn",
                                new AnnotationValues(oldValue: null, newValue: "UpdatedAt")
                            },
                        }),
                    Version = c.Binary(
                        annotations: new Dictionary<string, AnnotationValues>
                        {
                            { 
                                "ServiceTableColumn",
                                new AnnotationValues(oldValue: null, newValue: "Version")
                            },
                        }),
                    Event_EventID = c.Int(),
                })
            .PrimaryKey(t => t.UserID)
            .ForeignKey("dbo.Event", t => t.Event_EventID)
            .Index(t => t.Event_EventID);

    }

最后两行是我想要关注的内容

.ForeignKey("dbo.Event", t => t.Event_EventID)
.Index(t => t.Event_EventID);

这是在User表上创建一个到事件表的ForeignKey,即使我没有在User模型的任何地方定义Event_EventID。我认为迁移假设用户一次只能注册一个事件,因为我没有看到任何类型的查找表来确定哪些用户注册了哪些事件。

我已经尝试弄乱我的Event模型,将ForeignKey属性直接放在RegisteredUsers对象上,并发现这个错误很快。

如何强制EF识别出我需要多对多的用户与事件关系?或者我在假设这个问题上咆哮错误的树?

修改

我删除了ForeignKey属性并为每个属性设置了ICollection,我仍然有相同的错误,除了现在我有一个ADDITIONAL列,每个事件只允许一个用户,而没有EventUsers表。 / p>

public class User : CustomDataEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserID { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public DateTime Birthday { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string EmailAddress { get; set; }
    public byte[] Picture { get; set; }
    public virtual ICollection<Event> EventsRegisteredFor { get; set; }
}

public class Event : CustomDataEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int EventID { get; set; }
    public virtual User HostUser { get; set; }
    public string Description { get; set; }
    public virtual ICollection<User> RegisteredUsers { get; set; }
}

我最终得到了

        CreateTable(
            "dbo.Event",
            c => new
                {
                    EventID = c.Int(nullable: false, identity: true),
                    Description = c.String(nullable: false),
                    NumberOfUsers = c.Int(nullable: false),
                    StartDate = c.DateTime(nullable: false),
                    EndDate = c.DateTime(),
                    User_UserID = c.Int(),
                    HostUser_UserID = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.EventID)
            .ForeignKey("dbo.User", t => t.User_UserID)
            .ForeignKey("dbo.User", t => t.HostUser_UserID, cascadeDelete: true)
            .Index(t => t.User_UserID)
            .Index(t => t.HostUser_UserID);

        CreateTable(
            "dbo.User",
            c => new
                {
                    UserID = c.Int(nullable: false, identity: true),
                    Username = c.String(nullable: false),
                    Password = c.String(nullable: false),
                    Birthday = c.DateTime(nullable: false),
                    FirstName = c.String(nullable: false),
                    LastName = c.String(nullable: false),
                    EmailAddress = c.String(nullable: false),
                    Picture = c.Binary(),
                    Event_EventID = c.Int(),
                })
            .PrimaryKey(t => t.UserID)
            .ForeignKey("dbo.Event", t => t.Event_EventID)
            .Index(t => t.Event_EventID);

编辑2 我仔细检查了我可以使用的最基本信息。

public class User : CustomDataEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserID { get; set; }
    public string Username { get; set; }
    public virtual List<Event> Events { get; set; }
}
public class Event : CustomDataEntity
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int EventID { get; set; }
    public virtual User HostUser { get; set; }
    public virtual List<User> Users { get; set; }
}

但是,这个结构仍然没有给我必要的EventUsers或UserEvents表,它只是向数据库添加了一个允许单个UserID的列

 public override void Up()
    {
        CreateTable(
            "dbo.Event",
            c => new
                {
                    EventID = c.Int(nullable: false, identity: true),
                    User_UserID = c.Int(),
                    HostUser_UserID = c.Int(),
                })
            .PrimaryKey(t => t.EventID)
            .ForeignKey("dbo.User", t => t.User_UserID)
            .ForeignKey("dbo.User", t => t.HostUser_UserID)
            .Index(t => t.User_UserID)
            .Index(t => t.HostUser_UserID);

        CreateTable(
            "dbo.User",
            c => new
                {
                    UserID = c.Int(nullable: false, identity: true),
                    Username = c.String(),
                    Event_EventID = c.Int(),
                })
            .PrimaryKey(t => t.UserID)
            .ForeignKey("dbo.Event", t => t.Event_EventID)
            .Index(t => t.Event_EventID);

    }

2 个答案:

答案 0 :(得分:0)

对于多对多关系,只需在每个模型中添加一个集合:

用户模型中的

添加:

public virtual ICollection Events {set;得到; } //多对多

并在事件模型中添加:

public virtual ICollection Users {set;得到; } //多对多

您不需要使用任何其他外键。

实体框架会自动创建EventUsers表,您无法从dbcontext访问此表。 (你不需要太多访问权限)

但是如果你想访问EventUsers Table,你应该删除用户和事件之间的多对多关系,创建一个新模型,例如EventUsers,并建立从用户到eventusers以及从event到eventuse的一对多关系。 / p>

答案 1 :(得分:0)

在多对多关系中,它将创建第三个表,其中包括两个表的主键,例如

public class User
{
    [Key]
    public int UserID { get; set; }
    public string Username { get; set; }
    public List<Event> Events { get; set; }
}
public class Event
{
    [Key]
    public int EventID { get; set; }
    public List<User> Users { get; set; }
}

请注意,我在list类中使用user个事件,在event类中使用相同的事件,这意味着用户可以拥有多个事件,而事件可以拥有多个用户({{1} }) 因此,当我添加迁移时,它将创建第三个表名many to many,其中包含两个表的外键。

修改

你已经使用了UserEvent它创建了一对多的关系,所以你绑定只创建一个很多对很多的关系,所以不需要public virtual User HostUser { get; set; }