实体框架认为存在的列不存在

时间:2017-10-02 14:01:38

标签: c# entity-framework asp.net-identity

我有两张桌子:

InboxEvent
    int Id
    Visitor Owner
    [ForeignKey("Owner")]
    string OwnerId
    Visitor CausingUser
    [ForeignKey("CausingUser")]
    string CausingUserId

Visitor
    string Id

OwnerId和CausingUserId都指向了Visitor表,但在Sql Server Entity Framework中已经进入并创建了InboxEvent表,如下所示:

FK OwnerId
FK CausingUserId
FK Visitor_Id

当然,它发明了一个专栏:

NVarChar(128) Visitor_Id

好的......很奇怪......很简单,我会通过手动迁移杀死流浪列:

public partial class KillInboxEventVisitor_Id : DbMigration
{
    public override void Up()
    {
        DropForeignKey("dbo.InboxEvent", "Visitor_Id", "dbo.AspNetUsers");
        DropIndex("dbo.InboxEvent", "IX_Visitor_Id");
        DropColumn("dbo.InboxEvent", "Visitor_Id");
    }

很好,它已经消失了!现在......每次我试图让EF保存一个InboxEvent:

db.InboxEvents.Add(new InboxEvent {...
await db.SaveChangesAsync();

EF爆炸

SqlException: Invalid column name 'Visitor_Id'.

如何判断基础EF模型这个想象的列是不存在的?

编辑/更多信息

这是简单的Entity Framework 6.x,带有Asp.Net/OWIN Identity Framework,而不是较新的EF7 / Core。

我被要求展示全班。很高兴,但是,坚持你的屁股,他们在上面缩写是有原因的:

public class InboxEvent : IOwnerId
{
    public int Id { get; set; }

    [Index("IX_UserRead", 2)]
    public DateTime CreatedOn { get; set; }

    /// <summary>
    /// The user whose Inbox this event is deposited into.
    /// </summary>
    [ForeignKey("Owner"), Required]
    [MaxLength(128)]
    [Index("IX_UserRead", 0), Index]
    public string OwnerId { get; set; }
    public Visitor Owner { get; set; }

    [Index("IX_EventType_RelatedId1", 0)]
    public InboxEventType EventType { get; set; }

    public Posting.PostCore Post { get; set; }
    [ForeignKey("Post")]
    public int? PostId { get; set; }

    public Posting.PostReply Reply { get; set; }
    [ForeignKey("Reply")]
    public int? ReplyId { get; set; }

    [Index("IX_UserRead", 1)]
    public bool IsRead { get; set; }

    /// <summary>
    /// The user, if any, that caused/triggered this event. For example if A upvotes B, this is A, and B is Visitor.
    /// </summary>
    [ForeignKey("CausingUser")]
    [MaxLength(128)]
    public string CausingUserId { get; set; }
    public Visitor CausingUser { get; set; }


    [Index]
    [Index("IX_EventType_RelatedId1", 1)]
    public int RelatedId1 { get; set; }

    public int RelatedId2 { get; set; }



    public InboxEvent()
    {
        CreatedOn = DateTime.UtcNow;
    }
}

public class Visitor : IdentityUser<string, LoginIdentity, StandardUserRole, IdentityUserClaim>, IVisitor
{
    [MaxLength(22), Column(TypeName = "Char"), Index]
    public string Uid { get; set; }

    [MaxLength(300), Index]
    public string FirstName { get; set; }

    [MaxLength(300), Index]
    public string LastName { get; set; }

    public DateTime CreatedOn { get; set; }
    public DateTime MemberOn { get; set; }


    public int Invites { get; set; }
    public int Score { get; set; }

    public bool ShouldReceiveReplyNotifications { get; set; }
    public DateTime LastEmailNotified { get; set; }

    [MaxLength(100), Column(TypeName="VarChar")]
    public string ProfilePic { get; set; }

    public ICollection<UserPhoto> UserPhotos { get; set; }
    public StaticImage StaticImage { get; set; }


    // BioViewModel
    [MaxLength(100)]
    public string Nickname { get; set; }
    [MaxLength(400)]    // TODO Normalize
    public string Disciplines { get; set; }
    [MaxLength(1000)]
    public string MissionStatement { get; set; }
    [MaxLength(100)]
    public string Tagline { get; set; }

    // SkillsViewModel
    [MaxLength(400)]
    public string SkillsKnown { get; set; }
    [MaxLength(400)]
    public string SkillsToLearn { get; set; }

    // PrefsViewModel
    [MaxLength(10)]
    public string PhoneCountryCode { get; set; }
    //[MaxLength(20)]
    //public string PhoneNumber { get; set; }   // Already in base OWIN User model

    public ChatService ChatService { get; set; }
    [MaxLength(100)]
    public string ChatHandle { get; set; }

    public byte PrefIpOpenness { get; set; }
    public byte PrefNonProfit { get; set; }
    public byte PrefMature { get; set; }

    public PrivacyLevel PrivacyNameCountryCity { get; set; }
    public PrivacyLevel PrivacyBio { get; set; }
    public PrivacyLevel PrivacySites { get; set; }
    public PrivacyLevel PrivacyCompanies { get; set; }
    public PrivacyLevel PrivacySkills { get; set; }
    public PrivacyLevel PrivacyContactInfo { get; set; }
    public PrivacyLevel PrivacyCollabPrefs { get; set; }

    public bool WantMonthlyNewsletter { get; set; }
    public bool WantToMentor { get; set; }
    public bool WantToVetProjects { get; set; }
    public bool WantToReviewProjects { get; set; }
    public bool WantToGiveFeedback { get; set; }

    // CommitmentViewModel
    public CommitmentChoice CommitmentChoice { get; set; }
    [MaxLength(1000)]
    public string CommitmentText { get; set; }


    public ICollection<CountryZip> CountryZips { get; set; }
    public ICollection<Org> Orgs { get; set; }
    public ICollection<UserSite> UserSites { get; set; }


    public ICollection<DraftData> Drafts { get; set; }
    public ICollection<Visitor_Team> Teams { get; set; }

    public ICollection<InboxEvent> Inbox { get; set; }
    public ICollection<SubscribedPost> PostSubscriptions { get; set; }



    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<Visitor, string> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }


    public Visitor()
    {
        CreatedOn = (DateTime)SqlDateTime.MinValue;
        MemberOn = (DateTime)SqlDateTime.MinValue;
        LastEmailNotified = (DateTime)SqlDateTime.MinValue;
    }
}

Db确实有一个OnModelsCreating虽然它不太可能与此相关:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        var entity = modelBuilder.Entity<Visitor>();
        // By default this is nvarchar max? Uh?
        entity.Property(v => v.PhoneNumber).HasMaxLength(20);
    }

1 个答案:

答案 0 :(得分:2)

VisitorInboxEvent之间有三种关联。你最初展示的两个:

public class InboxEvent : IOwnerId
{
    ...
    [ForeignKey("Owner"), Required]
    public string OwnerId { get; set; }
    public Visitor Owner { get; set; }

    [ForeignKey("CausingUser")]
    public string CausingUserId { get; set; }
    public Visitor CausingUser { get; set; }
    ...
}

public class Visitor : IdentityUser<string, ...
{
    ...
    public ICollection<InboxEvent> Inbox { get; set; }
    ...
}

如果没有进一步通知,EF将假设这些关联彼此独立:它将创建三个FK,其中Visitor_Id用于后一个关联。

您可能希望InboxEvent.OwnerVisitor.Inbox成为一个关联的两端,但EF并不知道这一点,也不会猜测。您必须明确说明,例如使用[InverseProperty]属性:

public class InboxEvent : IOwnerId
{
    ...
    [ForeignKey("Owner"), Required]
    public string OwnerId { get; set; }

    [InverseProperty("Inbox")]
    public Visitor Owner { get; set; }
    ...
}