EF Code First Approach: Confused in EF Foreign Key constraint by fluent syntax - entity-framework

I am trying to create a foreign key relation ship with fluent syntax using EF code first approach.
My entities are as follows,
public partial class Defect
{
public int DefectID { get; set; }
public decimal ReleaseNo { get; set; }
public int BuildNo { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string StepsToReproduce { get; set; }
public int ApplicationModuleID { get; set; }
public int SeverityLevel { get; set; }
public string LoggedBy { get; set; }
public Nullable<System.DateTime> LoggedOn { get; set; }
public string LastModifiedBy { get; set; }
public Nullable<System.DateTime> LastModifiedOn { get; set; }
public string AssignedTo { get; set; }
public string Status { get; set; }
public string ResolutionNote { get; set; }
public Nullable<System.DateTime> ResolvedOn { get; set; }
public int ProjectID { get; set; }
public virtual SeverityIndex SeverityIndex { get; set; }
public virtual User LoggedByUser { get; set; }
public virtual User LastModifiedUser { get; set; }
public virtual User AssignedToUser { get; set; }
public virtual Project Project { get; set; }
}
public class DefectMap:EntityTypeConfiguration<Defect>
{
public DefectMap()
{
this.HasKey(d => d.DefectID);
this.ToTable("Defect");
this.Property(d => d.DefectID)
.IsRequired()
.HasColumnName("DefectID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(d => d.Description)
.IsRequired()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(2000)
.HasColumnName("Description")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(d => d.StepsToReproduce)
.IsOptional()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(4000)
.HasColumnName("StepsToReproduce")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(d => d.LastModifiedBy)
.IsOptional()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(10)
.HasColumnName("LastModifiedBy")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(d => d.AssignedTo)
.IsOptional()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(10)
.HasColumnName("AssignedTo")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(d => d.Status)
.IsOptional()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(50)
.HasColumnName("Status")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(d => d.ResolutionNote)
.IsOptional()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(4000)
.HasColumnName("ResolutionNote")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.HasRequired(p => p.Project).WithMany(p => p.DefectList).HasForeignKey(p => p.ProjectID);
this.HasRequired(s => s.SeverityIndex).WithMany(s => s.DefectList).HasForeignKey(s => s.SeverityLevel).WillCascadeOnDelete();
this.HasOptional(u => u.AssignedToUser).WithMany(u => u.AssignedToUserList).HasForeignKey(u => u.AssignedTo).WillCascadeOnDelete();
this.HasOptional(u => u.LastModifiedUser).WithMany(u => u.ModifiedByUserList).HasForeignKey(u => u.LastModifiedBy);
this.HasRequired(u => u.LoggedByUser).WithMany(u => u.LoggedByUserList).HasForeignKey(u => u.LoggedBy);
}
public partial class Project
{
public Project()
{
ApplicationModuleList = new List<ApplicationModule>();
DefectList = new List<Defect>();
UserList = new List<User>();
}
public int ID { get; set; }
public string ProjectName { get; set; }
public string ProjectManager { get; set; }
public Nullable<System.DateTime> ProjectStartDate { get; set; }
public Nullable<System.DateTime> ProjectEstimatedEndDate { get; set; }
public Nullable<System.DateTime> ProjectActualEndDate { get; set; }
public Nullable<int> ProjectBillingModel { get; set; }
public Nullable<decimal> ProjectEstimatedBudget { get; set; }
public Nullable<decimal> ProjectActualBudget { get; set; }
public Nullable<int> ProjectPortfolio { get; set; }
public Nullable<decimal> ProjectBillingRate { get; set; }
public Nullable<int> ProjectEstimatedManHours { get; set; }
public Nullable<int> ProjectActualManHours { get; set; }
public Nullable<int> ProjectIsApproved { get; set; }
public virtual ICollection<ApplicationModule> ApplicationModuleList { get; set; }
public virtual ICollection<Defect> DefectList { get; set; }
public virtual ICollection<User> UserList { get; set; }
public virtual BillingModel BillingModel { get; set; }
public virtual Portfolio Portfolio { get; set; }
public virtual ApprovalStatus ApprovalStatus { get; set; }
}
public class ProjectMap:EntityTypeConfiguration<Project>
{
public ProjectMap()
{
this.HasKey(p => p.ID);
this.ToTable("Projects");
this.Property(p => p.ID)
.HasColumnName("ID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
this.Property(p => p.ProjectName)
.HasColumnName("ProjectName")
.HasMaxLength(200)
.IsRequired()
.IsVariableLength()
.IsUnicode()
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.HasOptional(p => p.BillingModel).WithMany(p=>p.Projects).HasForeignKey(p => p.ProjectBillingModel).WillCascadeOnDelete();
this.HasOptional(p => p.Portfolio).WithMany(p=>p.Projects).HasForeignKey(p => p.ProjectPortfolio).WillCascadeOnDelete();
this.HasOptional(p => p.ApprovalStatus).WithMany(p=>p.Projects).HasForeignKey(p => p.ProjectIsApproved).WillCascadeOnDelete();
}
}
I am trying code first approach for database creation using fluent API.
However when I run the code I get error saying
*Introducing FOREIGN KEY constraint 'FK_dbo.User_dbo.Projects_ProjectID' on table 'User' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors*
The same error appears for AssignedTo column.
Here I am trying to implement logic where, A project can have many defects and a defect should have an associated Project ID (i.e one to many relationship between project and defect).
Can anyone suggest what is wrong with the code and where should I rectify the code to get things working?
Thanks in advance!!!

EF has Cascade delete on by default, and this will cause problems with your design - as per the error message.
Either add the following
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
or include
WillCascadeOnDelete(false)
in your fluent API

Related

Change many-to-one relationship into one-to-one EF

I am building a platform using .NET CORE 2.1, and it is about questions and answers. Before I started I scaffolded my existing DB into the .net project so I got the model up and running.
Scaffold-DbContext "Server=(localdb)\mssqllocaldb;Database=MYDATABASE;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
But it generated QUESTION and QUESTION_DETAIL with a many-to-one relation ship whereas QUESTION should only have 1 QUESTION DETAIl. But when I am trying to change it with the fluent API in my context it gives an error:
Cannot Convert lambda expression to type 'Type' because it is not a delegated type
Here are my 2 model classes
public partial class Question
{
public Question()
{
AnswerClientBot = new HashSet<AnswerClientBot>();
InverseOriginalQuestion = new HashSet<Question>();
QuestionFollowUpFollowUpQuestion = new HashSet<QuestionFollowUp>();
QuestionFollowUpOriginalQuestion = new HashSet<QuestionFollowUp>();
}
public int Id { get; set; }
public int BotInstanceId { get; set; }
public string LanguageCode { get; set; }
public string Question1 { get; set; }
public int? OriginalQuestionId { get; set; }
[ForeignKey("QuestionDetail")]
public int QuestionDetailId { get; set; }
public Instance BotInstance { get; set; }
public Question OriginalQuestion { get; set; }
public QuestionDetail QuestionDetail { get; set; }
public ICollection<AnswerClientBot> AnswerClientBot { get; set; }
public ICollection<Question> InverseOriginalQuestion { get; set; }
public ICollection<QuestionFollowUp> QuestionFollowUpFollowUpQuestion { get; set; }
public ICollection<QuestionFollowUp> QuestionFollowUpOriginalQuestion { get; set; }
}
public partial class QuestionDetail
{
public int Id { get; set; }
public int OriginalQuestionId { get; set; }
public string Topic { get; set; }
public string Intent { get; set; }
public string CustDetail01 { get; set; }
public string CustDetail02 { get; set; }
public string CustDetail03 { get; set; }
public string CustDetail04 { get; set; }
public string CustDetail05 { get; set; }
public string Keywords { get; set; }
public Question OriginalQuestion { get; set; }
}
And this is the context I am trying to change, the error occurs on
HasForeignKey(d => d.OriginalQuestionId)
modelBuilder.Entity<QuestionDetail>(entity =>
{
entity.ToTable("QuestionDetail", "Bot");
entity.Property(e => e.CustDetail01)
.HasColumnName("CUST_Detail01")
.HasMaxLength(250)
.IsUnicode(false);
entity.Property(e => e.CustDetail02)
.HasColumnName("CUST_Detail02")
.HasMaxLength(250)
.IsUnicode(false);
entity.Property(e => e.CustDetail03)
.HasColumnName("CUST_Detail03")
.HasMaxLength(250)
.IsUnicode(false);
entity.Property(e => e.CustDetail04)
.HasColumnName("CUST_Detail04")
.HasMaxLength(250)
.IsUnicode(false);
entity.Property(e => e.CustDetail05)
.HasColumnName("CUST_Detail05")
.HasMaxLength(250)
.IsUnicode(false);
entity.Property(e => e.Intent)
.HasMaxLength(250)
.IsUnicode(false);
entity.Property(e => e.Keywords)
.HasMaxLength(250)
.IsUnicode(false);
entity.Property(e => e.Topic)
.HasMaxLength(250)
.IsUnicode(false);
entity.HasOne(d => d.OriginalQuestion)
.WithOne(p => p.QuestionDetail)
.HasForeignKey(d => d.OriginalQuestionId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Bot_QuestionDetail_OriginalQuestionId");
});
Does anyone have any clue how I can fix this? Thank you!
Declare both classes with navigation properties to each other. Mark one of the tables (the dependent table) with the ForeignKey attribute on its Primary Key. EF infers 1-to-1 from this:
public class Question
{
...
// [ForeignKey("QuestionDetail")]
// public int QuestionDetailId { get; set; }
public QuestionDetail QuestionDetail { get; set; }
...
}
public partial class QuestionDetail
{
//public int Id { get; set; }
[ForeignKey("Question")]
public int QuestionId { get; set; }
...
public Question Question { get; set; }
}
So I found this Cannot convert lambda expression to type 'object' because it is not a delegate type stackoverflow post, and at the start I tried to strong type it but didn't know really how to but eventually I figured it out. So I changed it to HasForeignKey<Question>(d => d.OriginalQuestionId) which worked for me.

Entity Framework Core: How to solve Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths

I'm using Entity Framework Core with Code First approach but recieve following error when updating the database:
Introducing FOREIGN KEY constraint 'FK_AnEventUsers_Users_UserId' on table 'AnEventUsers' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.
My entities are these:
public class AnEvent
{
public int AnEventId { get; set; }
public DateTime Time { get; set; }
public Gender Gender { get; set; }
public int Duration { get; set; }
public Category Category { get; set; }
public int MinParticipants { get; set; }
public int MaxParticipants { get; set; }
public string Description { get; set; }
public Status EventStatus { get; set; }
public int MinAge { get; set; }
public int MaxAge { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public ICollection<AnEventUser> AnEventUsers { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class User
{
public int UserId { get; set; }
public int Age { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Gender Gender { get; set; }
public double Rating { get; set; }
public ICollection<AnEventUser> AnEventUsers { get; set; }
}
public class AnEventUser
{
public int AnEventId { get; set; }
public AnEvent AnEvent { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class ApplicationDbContext:DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AnEventUser>()
.HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<AnEventUser>()
.HasKey(t => new { t.AnEventId, t.UserId });
modelBuilder.Entity<AnEventUser>()
.HasOne(pt => pt.AnEvent)
.WithMany(p => p.AnEventUsers)
.HasForeignKey(pt => pt.AnEventId);
modelBuilder.Entity<AnEventUser>()
.HasOne(eu => eu.User)
.WithMany(e => e.AnEventUsers)
.HasForeignKey(eu => eu.UserId);
}
public DbSet<AnEvent> Events { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<AnEventUser> AnEventUsers { get; set; }
}
The issue I thought was that if we delete a User the reference to the AnEvent will be deleted and also the reference to AnEventUser will also be deleted, since there is a reference to AnEventUser from AnEvent as well we get cascading paths. But I remove the delete cascade from User to AnEventUser with:
modelBuilder.Entity<AnEventUser>()
.HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);
But the error doesn't get resolved, does anyone see what is wrong? Thanks!
In your sample code in OnModelCreating you have declared modelBuilder.Entity<AnEventUser>().HasOne(e => e.User)... twice: at start of method and at end.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AnEventUser>() // THIS IS FIRST
.HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<AnEventUser>()
.HasKey(t => new { t.AnEventId, t.UserId });
modelBuilder.Entity<AnEventUser>()
.HasOne(pt => pt.AnEvent)
.WithMany(p => p.AnEventUsers)
.HasForeignKey(pt => pt.AnEventId);
modelBuilder.Entity<AnEventUser>() // THIS IS SECOND.
.HasOne(eu => eu.User) // THIS LINES
.WithMany(e => e.AnEventUsers) // SHOULD BE
.HasForeignKey(eu => eu.UserId); // REMOVED
}
Second call overrides first. Remove it.
This is what I did from the answer of Dmitry,
and It worked for me.
Class:
public class EnviornmentControls
{
public int Id { get; set; }
...
public virtual Environment Environment { get; set; }
}
And it's Mapping
public EnviornmentControlsMap(EntityTypeBuilder<EnviornmentControls> entity)
{
entity.HasKey(m => m.Id);
entity.HasOne(m => m.Environment)
.WithMany(m => m.EnviornmentControls)
.HasForeignKey(m => m.EnvironmentID)
.OnDelete(DeleteBehavior.Restrict); // added OnDelete to avoid sercular reference
}
These solutions didn't work for my case, but I found a way. I am not quite sure yet if it is safe but there's just something that's happening with deleting. So I modified the generated Migration File instead of putting an override.
onDelete: ReferentialAction.Cascade
The reason I did this because all the overriding mentioned above is not working for me so I manually removed the code which relates to Cascading of Delete.
Just check which specific relation being mentioned at the error so you can go straightly.
Hope this will be able to help for some people who's having the same issue as mine.
public Guid? UsuarioId { get; set; }
builder.Entity<Orcamentacao>()
.HasOne(x => x.Usuario)
.WithMany(x => x.Orcamentacaos)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired(false)
.HasForeignKey(x => x.UsuarioId);

Entity Framework many to many fluent API

I'm working with an existing database whose schema is fixed.
There are 3 many-to-many relations, Contact-Group, Contact-Department and Contact-Team.
There is a common table, ContactRelation that acts as the middle table for all 3 relations.
public class Contact
{
[Column("CtcID")]
public int Id { get; set; }
[Column("CtcFirstName")]
public string FirstName { get; set; }
[Column("CtcFamilyName")]
public string LastName { get; set; }
public virtual ICollection<ContactRelation> GroupRelations { get; set; }
public virtual ICollection<ContactRelation> DepartmentRelations { get; set; }
public virtual ICollection<ContactRelation> TeamRelations { get; set; }
}
public class Group
{
[Key, Column("GRID")]
public int Id { get; set; }
[Column("GRName")]
public string Name { get; set; }
public virtual ICollection<ContactRelation> ContactRelations { get; set; }
}
public class Department
{
[Key, Column("DEPID")]
public int Id { get; set; }
[Column("DEPName")]
public string Name { get; set; }
public virtual ICollection<ContactRelation> ContactRelations { get; set; }
}
public class Team
{
[Key, Column("TMID")]
public int Id { get; set; }
[Column("TransCode")]
public string TransCode { get; set; }
public virtual ICollection<ContactRelation> ContactRelations { get; set; }
}
public class ContactRelation
{
[Key]
[Column("CtcRelnID")]
public int Id { get; set; }
[Column("GRID")]
public int GroupId { get; set; }
[Column("DEPID")]
public int DepartmentId { get; set; }
[Column("TMID")]
public int TeamId { get; set; }
[Column("CUCtcID")]
public int ContactId { get; set; }
[Column("RCode")]
public string RoleCode { get; set; }
}
In my mapping, I have the following code:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Group>()
.HasMany(g => g.ContactRelations)
.WithRequired()
.HasForeignKey(r => r.GroupId);
modelBuilder.Entity<Department>()
.HasMany(c => c.ContactRelations)
.WithRequired()
.HasForeignKey(r => r.DepartmentId);
modelBuilder.Entity<Team>()
.HasMany(s => s.ContactRelations)
.WithRequired()
.HasForeignKey(r => r.TeamId);
modelBuilder.Entity<Contact>()
.HasMany(c => c.GroupRelations)
.WithRequired()
.HasForeignKey(r => r.ContactId);
modelBuilder.Entity<Contact>()
.HasMany(c => c.DepartmentRelations)
.WithRequired()
.HasForeignKey(r => r.ContactId);
modelBuilder.Entity<Contact>()
.HasMany(c => c.TeamRelations)
.WithRequired()
.HasForeignKey(r => r.ContactId);
}
I then try to execute the following query:
var ctc = repo.Contacts
.Include("GroupRelations")
.Include("DepartmentRelations")
.FirstOrDefault(c => c.FirstName.ToLower() == "jason");
and I keep getting error:
System.Data.SqlClient.SqlException:
Invalid column name 'Contact_Id1'.
Invalid column name 'Contact_Id'.
Invalid column name 'Contact_Id1'.
Invalid column name 'Contact_Id2'.
I read somewhere that a table cannot participate in more than one many-to-many relations. Is that true? Is it because the ContactRelation table is used more than once that I'm getting this error?
If so, what's the correct way to map these relations, without modifying the database schema.?
PS: I'm working with EF6.1
Thanks for your help.
Remove this mapping
modelBuilder.Entity<Contact>()
.HasMany(c => c.TeamRelations)
.WithRequired()
.HasForeignKey(r => r.ContactId);
and then try executing your query.

Why am I getting Invalid column name on field names that don't exist in my model?

I am querying an entity with EF 5.0 Code First / DbContext. I am getting the following errors:
Invalid column name 'RetainedEarningsAccount_Key'.
Invalid column name 'PLSummaryAccount_Key'.
However, neither of these fields exist in the model. I assume some default configuration/mapping is happening here, but I don't know what it is. Here is the model class in question:
public GLEntity()
{
this.AccessEntities = new HashSet<AccessEntity>();
this.BankAccountGLAccounts = new HashSet<BankAccountGLAccount>();
this.BatchRestrictionEntities = new HashSet<BatchRestrictionEntity>();
this.BudgetVersions = new HashSet<BudgetVersion>();
this.CalendarCrossRefs = new HashSet<CalendarCrossRef>();
this.ConsolDetails = new HashSet<ConsolDetail>();
this.ConsolHeaders = new HashSet<ConsolHeader>();
this.DefaultBudgetVersions = new HashSet<DefaultBudgetVersion>();
this.Departments = new HashSet<Department>();
this.ExpenseCodeDetails = new HashSet<ExpenseCodeDetail>();
this.GLAccounts = new HashSet<GLAccount>();
this.Journals = new HashSet<Journal>();
this.PostingRules = new HashSet<PostingRule>();
this.Processes = new HashSet<Process>();
this.Properties = new HashSet<Property>();
this.RecurringJournals = new HashSet<RecurringJournal>();
this.RecurringTransactionGLs = new HashSet<RecurringTransactionGL>();
this.EntitiesAlternate = new HashSet<GLEntity>();
this.GLIntercompaniesDestinationEntities = new HashSet<GLIntercompany>();
this.GLIntercompaniesSourceEntities = new HashSet<GLIntercompany>();
this.TransGLs = new HashSet<TransGL>();
}
public System.Guid Key { get; set; }
public string EntityID { get; set; }
public string Description { get; set; }
public Nullable<short> CurrentFiscalYear { get; set; }
public Nullable<short> CurrentPrd { get; set; }
public string EntityType { get; set; }
public string AllowPostingYN { get; set; }
public string NextJournal { get; set; }
public Nullable<System.Guid> CompanyKey { get; set; }
public Nullable<System.Guid> RetainedEarningsAcctKey { get; set; }
public Nullable<System.Guid> PLSummaryAcctKey { get; set; }
public string AccountingType { get; set; }
public string UserCreated { get; set; }
public System.DateTime Created { get; set; }
public string UserEdited { get; set; }
public Nullable<System.DateTime> Edited { get; set; }
public Nullable<System.Guid> AlternateEntityKey { get; set; }
public string TrackJobs { get; set; }
public string TrackUnits { get; set; }
public virtual ICollection<AccessEntity> AccessEntities { get; set; }
public virtual ICollection<BankAccountGLAccount> BankAccountGLAccounts { get; set; }
public virtual ICollection<BatchRestrictionEntity> BatchRestrictionEntities { get; set; }
public virtual ICollection<BudgetVersion> BudgetVersions { get; set; }
public virtual ICollection<CalendarCrossRef> CalendarCrossRefs { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<ConsolDetail> ConsolDetails { get; set; }
public virtual ICollection<ConsolHeader> ConsolHeaders { get; set; }
public virtual ICollection<DefaultBudgetVersion> DefaultBudgetVersions { get; set; }
public virtual ICollection<Department> Departments { get; set; }
public virtual ICollection<ExpenseCodeDetail> ExpenseCodeDetails { get; set; }
public virtual ICollection<GLAccount> GLAccounts { get; set; }
public virtual ICollection<Journal> Journals { get; set; }
public virtual ICollection<PostingRule> PostingRules { get; set; }
public virtual ICollection<Process> Processes { get; set; }
public virtual ICollection<Property> Properties { get; set; }
public virtual ICollection<RecurringJournal> RecurringJournals { get; set; }
public virtual ICollection<RecurringTransactionGL> RecurringTransactionGLs { get; set; }
public virtual ICollection<GLEntity> EntitiesAlternate { get; set; }
public virtual GLEntity EntityAlternate { get; set; }
public virtual ICollection<GLIntercompany> GLIntercompaniesDestinationEntities { get; set; }
public virtual ICollection<GLIntercompany> GLIntercompaniesSourceEntities { get; set; }
public virtual ICollection<TransGL> TransGLs { get; set; }
public virtual GLAccount RetainedEarningsAccount { get; set; }
public virtual GLAccount PLSummaryAccount { get; set; }
}
And here is the mapping:
public GLEntity_Mapping()
{
this.HasKey(t => t.Key);
this.ToTable("tblEntity");
this.Property(t => t.Key).HasColumnName("KeyGUID");
this.Property(t => t.EntityID).HasColumnName("EntityID").IsUnicode(false).HasMaxLength(10);
this.Property(t => t.Description).HasColumnName("Description").IsUnicode(false).HasMaxLength(50);
this.Property(t => t.CurrentFiscalYear).HasColumnName("CurrentFiscalYear");
this.Property(t => t.CurrentPrd).HasColumnName("CurrentPrd");
this.Property(t => t.EntityType).HasColumnName("EntityType").IsUnicode(false).IsFixedLength().HasMaxLength(1);
this.Property(t => t.AllowPostingYN).HasColumnName("AllowPostingYN").IsUnicode(false).IsFixedLength().HasMaxLength(1);
this.Property(t => t.NextJournal).HasColumnName("NextJournal").IsUnicode(false).HasMaxLength(20);
this.Property(t => t.CompanyKey).HasColumnName("Company");
this.Property(t => t.RetainedEarningsAcctKey).HasColumnName("RetainedEarningsAcct");
this.Property(t => t.PLSummaryAcctKey).HasColumnName("PLSummaryAcct");
this.Property(t => t.AccountingType).HasColumnName("AccountingType").IsUnicode(false).IsFixedLength().HasMaxLength(1);
this.Property(t => t.UserCreated).HasColumnName("UserCreated").IsRequired().IsUnicode(false).HasMaxLength(50);
this.Property(t => t.Created).HasColumnName("Created");
this.Property(t => t.UserEdited).HasColumnName("UserEdited").IsUnicode(false).HasMaxLength(50);
this.Property(t => t.Edited).HasColumnName("Edited");
this.Property(t => t.AlternateEntityKey).HasColumnName("AlternateEntity");
this.Property(t => t.TrackJobs).HasColumnName("TrackJobs").IsUnicode(false).IsFixedLength().HasMaxLength(1);
this.Property(t => t.TrackUnits).HasColumnName("TrackUnits").IsUnicode(false).IsFixedLength().HasMaxLength(1);
this.HasOptional(t => t.Company).WithMany(t => t.Entities).HasForeignKey(d => d.CompanyKey);
this.HasOptional(t => t.EntityAlternate).WithMany(t => t.EntitiesAlternate).HasForeignKey(d => d.AlternateEntityKey);
}
Why am I getting an error on non-existent properties?
Because of the abbreviation Acct instead of Account in these properties...
public Nullable<System.Guid> RetainedEarningsAcctKey { get; set; }
public Nullable<System.Guid> PLSummaryAcctKey { get; set; }
...EF conventions do not recognize the properties as foreign keys for
public virtual GLAccount RetainedEarningsAccount { get; set; }
public virtual GLAccount PLSummaryAccount { get; set; }
You can either rename the FK properties to RetainedEarningsAccountKey and PLSummaryAccountKey. EF should recognize them correctly then according to the rule "FK property name = Navigation property name + primary key name of target entity".
Or define the properties as FKs with Fluent API in your GLEntity_Mapping:
this.HasOptional(t => t.RetainedEarningsAccount)
.WithMany(a => a.SomeInverseCollection1)
.HasForeignKey(t => t.RetainedEarningsAcctKey);
this.HasOptional(t => t.PLSummaryAccount)
.WithMany(a => a.SomeInverseCollection2)
.HasForeignKey(t => t.PLSummaryAcctKey);
SomeInverseCollection1/2 are the related collections in GLAccount or use WithMany() without lambda parameter if there are no inverse collections in that class.

Mapping Many-to-Many Relationship With Defined Middle Entity in Entity Framework 5

I'm trying to define a many-to-many relationship explicitly. By explicitly, I mean that I'm defining the middle entity and configuring it using the Fluent API. Below is my code:
public class ContentType
{
public Int64 Id { get; set; }
public Guid SID { get; set; }
public String Name { get; set; }
public ContentType Parent { get; set; }
public Nullable<Int64> ParentId { get; set; }
public Category Category { get; set; }
public Nullable<Int64> CategoryId { get; set; }
public Boolean IsLocked { get; set; }
public virtual ICollection<ContentTypeColumn> ContentTypeColumns { get; set; }
}
public class Column
{
public Int64 Id { get; set; }
public Guid SID { get; set; }
public String SchemaName { get; set; }
public DataType DataType { get; set; }
public Int32 DataTypeId { get; set; }
public virtual ICollection<ContentTypeColumn> ContentTypeColumns { get; set; }
}
public class ContentTypeColumn
{
public Int64 Id { get; set; }
public Int64 ColumnId { get; set; }
public Column Column { get; set; }
public ContentType ContentType { get; set; }
public Int64 ContentTypeId { get; set; }
public Boolean IsRequired { get; set; }
public Boolean IsCalculated { get; set; }
public String Title { get; set; }
public Boolean IsSystem { get; set; }
public Expression Expression { get; set; }
public Int32 ExpressionId { get; set; }
public virtual ICollection<ColumnRule> Rules { get; set; }
}
public class ContentTypeConfiguration : EntityTypeConfiguration<ContentType>
{
public ContentTypeConfiguration()
{
this.ToTable("ContentType");
this.Property(x => x.Id).HasColumnName("ContentTypeId").IsRequired();
this.Property(x => x.Name).HasMaxLength(30);
this.HasOptional(x => x.Parent)
.WithMany()
.HasForeignKey(x => x.ParentId);
this.Property(x => x.SID).IsRequired();
}
}
public class ContentTypeColumnConfiguration : EntityTypeConfiguration<ContentTypeColumn>
{
public ContentTypeColumnConfiguration()
{
this.ToTable("ContentTypeColumn");
this.HasRequired(x => x.ContentType)
.WithMany()
.HasForeignKey(x => x.ContentTypeId);
this.Property(x => x.Title).HasMaxLength(50).IsRequired();
this.Property(x => x.Id).HasColumnName("ContentTypeColumnId");
}
}
For some reason, two foreign keys are being created on the resultant ContentTypeColumn table. One is a nullable foreign key, the other is non-nullable. I want only the latter to be generated, and I have no idea where the nullable key is coming from.
Any thoughts?
This is wrong:
this.HasRequired(x => x.ContentType)
.WithMany()
.HasForeignKey(x => x.ContentTypeId);
You have reverse navigation property so you must use int in WithMany or EF will probably create two relations:
this.HasRequired(x => x.ContentType)
.WithMany(y => y.ContentTypeColumns)
.HasForeignKey(x => x.ContentTypeId);
Btw. this mapping should not be needed at all because it is discovered automatically through default conventions.