我有2个表:
InboxEvent
int Id
Visitor Owner
[ForeignKey("Owner")]
string OwnerId
Visitor CausingUser
[ForeignKey("CausingUser")]
string CausingUserId
Visitor
string Id
所有者和引起访问者表都指向访问者表,但是在SQL Server Entity中,框架已经进入并创建了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模型此想象的列不存在?
编辑/更多信息
这是普通的实体框架6.x,带有ASP.NET/OWIN身份框架,而不是较新的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确实有一个on modelscreating,尽管在这里不太可能相关:
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);
}
Visitor
和InboxEvent
之间有三个关联。您最初显示的两个:
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将假设这些关联彼此独立:它将创建三个FKS,其中Visitor_Id
用于后一个关联。
您可能希望InboxEvent.Owner
和Visitor.Inbox
成为一个关联的两个端,但是EF不知道,这不会猜测。您必须将其显式,例如使用[InverseProperty]
属性:
public class InboxEvent : IOwnerId
{
...
[ForeignKey("Owner"), Required]
public string OwnerId { get; set; }
[InverseProperty("Inbox")]
public Visitor Owner { get; set; }
...
}