Entity Framework 6 Lazy Loading not working - c#

I am having some trouble with EF6 lazy loading, code first to an existing database.
Here are the Entities that are giving me the issue, I have no idea why it is not working, everything I find online says it should be working.
public class User
{
public long UserId { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Token> Tokens { get; set; }
public virtual ICollection<Business> Businesses { get; set; }
public virtual ICollection<Candidate> Candidates { get; set; }
}
Here is the configuration mappings:
public class Token
{
public long TokenId { get; set; }
public long UserId { get; set; }
public Guid TokenValue { get; set; }
public DateTime ExpirationDate { get; set; }
public virtual User User { get; set; }
}
public TokenMap()
{
this.HasKey(t => t.TokenId);
this.Property(t => t.TokenValue)
.IsRequired();
this.Property(t => t.ExpirationDate)
.IsRequired();
this.ToTable("Tokens");
this.Property(t => t.TokenId).HasColumnName("TokenId");
this.Property(t => t.UserId).HasColumnName("UserId");
this.Property(t => t.TokenValue).HasColumnName("TokenValue");
this.Property(t => t.ExpirationDate).HasColumnName("ExpirationDate");
this.HasRequired(s => s.User)
.WithMany(s=>s.Tokens)
.HasForeignKey(s=>s.UserId);
}
public UserMap()
{
this.ToTable("Users");
this.HasKey(t => t.UserId);
this.Property(t => t.Email)
.IsRequired();
this.Property(t => t.FirstName)
.IsRequired();
this.Property(t => t.LastName)
.IsRequired();
this.HasMany(t => t.Businesses)
.WithMany(set => set.Users)
.Map(m =>
{
m.ToTable("BusinessUser");
m.MapLeftKey("UserId");
m.MapRightKey("BusinessId");
});
this.HasMany(s => s.Tokens)
.WithRequired(s => s.User)
.HasForeignKey(s => s.UserId);
this.HasMany(s => s.Candidates)
.WithOptional(s => s.User)
.HasForeignKey(s => s.UserId);
}
And here is a few snippets from the context:
public DbSet<Token> Token { get; set; }
public DbSet<User> User { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new TokenMap());
modelBuilder.Configurations.Add(new UserMap());
}
Whenever I do a SingleOrDefault on the Tokens entity the result' user is null.
Any idea what I am doing wrong? All the data in the database is right, and UserId does have a value.
Here is a more elaborate example of calling:
I am implementing the repository patern.
In the class doing the call' constructor I have:
context = new Consolid8ContextProvider();
uow = new UnitOfWork(context);
And then uow.Tokens.First(u => u.ExpirationDate > DateTime.Now && u.TokenValue == token);
Tokens is my TokenRepository that exposes the Tokens entity, and First is a wrapper for FirstOrDefault.
This results in a token object with all of the properties set except for the User navigation property

So I was using BreezeJS and it overrides your context with it's own settings, part of which is to set LazyLoading and EnableProxiesCreation to false.
So if you want to do queries outside of breeze you either have to implement a different constructor for your breeze provider or setting it per query as Slauma has suggested in the comments of the question.

Related

EF Core – Complicated Relationships

I have complicated relationships between these entities:
Country
Airport
Airline
Flight
Country has many Airlines and many Airports.
Airline has one Countries, the same about Airport.
Airline has many Flights,
Airport has many DepartureFlights and ArrivalFlights (both are Flight type).
Flight has one Airline and one DepartureAirport and one ArrivalAirport (both are Airport type).
Country can have no airlines and airports,
Airline can have no Flights,
Airport can have neither DepartureFlights nor ArrivalFlights.
What I am trying to do is when Country is deleted, then all related Airlines and Airports are deleted, also when Airline or DepartureAirport or ArrivalAirport are deleted, all related Flights are deleted also,
but when updating my db after the migration is created I'm getting an error:
Introducing FOREIGN KEY constraint "FK_Flights_Airports_DepartureAirport" on table "Flights" may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
How to implement this behavior and prevent an error?
Here are my models:
Country:
public class Country
{
public int Id { get; set; }
/* other properties */
public virtual ICollection<Airport>? Airports { get; set; }
public virtual ICollection<Airline>? Airlines { get; set; }
}
Airline:
public class Airline
{
public int Id { get; set; }
/* other properties */
public int CountryId { get; set; }
public virtual Country Country { get; set; }
public virtual ICollection<Flight>? Flights { get; set; }
}
Airport:
public class Airport
{
public int Id { get; set; }
public string Name { get; set; }
/* other properties */
public int CountryId { get; set; }
public virtual Country Country { get; set; }
public virtual ICollection<Flight>? DepartureFlights { get; set; }
public virtual ICollection<Flight>? ArrivalFlights { get; set; }
}
Flight:
public class Flight
{
public int Id { get; set; }
/* other properties */
public int AirlineId { get; set; }
public int DepartureAirportId { get; set; }
public int ArrivalAirportId { get; set; }
public virtual Airline Airline { get; set; }
public virtual Airport DepartureAirport { get; set; }
public virtual Airport ArrivalAirport { get; set; }
}
After all the DBContext file:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Airline> Airlines { get; set; }
public DbSet<Airport> Airports { get; set; }
public DbSet<Country> Countries { get; set; }
public DbSet<Flight> Flights { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Airline>(x =>
{
x.HasKey(a => a.Id);
x.HasOne(c => c.Country)
.WithMany(a => a.Airlines)
.HasForeignKey(a => a.CountryId)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity<Airport>(x =>
{
x.HasKey(a => a.Id);
x.HasOne(c => c.Country)
.WithMany(a => a.Airports)
.HasForeignKey(a => a.CountryId)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity<Country>(x =>
{
x.HasKey(c => c.Id);
});
modelBuilder.Entity<Flight>(x =>
{
x.HasKey(f => f.Id);
x.HasOne(a => a.Airline)
.WithMany(f => f.Flights)
.HasForeignKey(f => f.AirlineId)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
x.HasOne(a => a.DepartureAirport)
.WithMany(f => f.DepartureFlights)
.HasForeignKey(f => f.DepartureAirportId)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
x.HasOne(a => a.ArrivalAirport)
.WithMany(f => f.ArrivalFlights)
.HasForeignKey(f => f.ArrivalAirportId)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
}
}
How to implement this behavior and prevent an error?
This is officially known issue. Therefore, We have two ways to handle this scenario thus the error:
1. Change one or more of the relationships to not cascade delete.
In this scenario, we could make the Country relationship with Airport, Flight and Airlines optional by giving it a nullable foreign key property: for instance we can do something like:
.IsRequired(false);
Note: You can check our official document for more details.
2. Configure the database without one or more of these cascade deletes,
then ensure all dependent entities are loaded so that EF Core can
perform the cascading behavior.
Considering this appreach we can keep the Airport, Flight and Airlines relationship required and configured for cascade delete, but make this configuration only apply to tracked entities, not the database: So we can do somethng like below:
modelBuilder.Entity<Airline>(x =>
{
x.HasKey(a => a.Id);
x.HasOne(c => c.Country)
.WithMany(a => a.Airlines)
.HasForeignKey(a => a.CountryId)
.OnDelete(DeleteBehavior.ClientCascade);
.IsRequired(false);
});
modelBuilder.Entity<Airport>(x =>
{
x.HasKey(a => a.Id);
x.HasOne(c => c.Country)
.WithMany(a => a.Airports)
.HasForeignKey(a => a.CountryId)
.OnDelete(DeleteBehavior.ClientCascade);
.IsRequired(false);
});
Note: You can apply same for Flight as well. In addition, As you may know OnDelete(DeleteBehavior.ClientCascade); or ClientCascade allows the DBContext to delete entities even if there is a cyclic ref or LOCK on it. Please read the official guideline for more details here
add these lines in "OnModelCreating"
var cascades = modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetForeignKeys())
.Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade);
foreach (var fk in cascades)
fk.DeleteBehavior = DeleteBehavior.Restrict;

Why is Entity creating a key field when it is already defined?

I have several related domain models that are triggering the exception SqlException: Invalid column name 'ChecklistTemplate_Id'.
My domain model looks like:
public class Assignment
{
public long Id { get; set; }
public long ChecklistId { get; set; }
public DateTime InspectionDate { get; set; }
public long JobId { get; set; }
public Guid? EmployeeId { get; set; }
// TODO: Make the completion a nullable date time in the database and here
public DateTime CompletionDate { get; set; }
public virtual Job Job { get; set; }
public virtual Checklist Checklist { get; set; }
public virtual IList<Image> Images { get; set; }
public virtual IList<Attachment> Attachments { get; set; }
public virtual IList<Equipment> Equipments { get; set; }
}
My EntityTypeConfiguration class looks like:
internal class AssignmentConfiguration : EntityTypeConfiguration<Assignment>
{
public AssignmentConfiguration()
{
ToTable("Assignment");
HasKey(k => k.Id);
Property(a => a.ChecklistId)
.IsRequired();
Property(a => a.CompletionDate)
.IsOptional();
Property(a => a.EmployeeId)
.IsOptional();
Property(a => a.Id)
.IsRequired();
Property(a => a.InspectionDate)
.IsRequired();
Property(a => a.JobId)
.IsRequired();
HasRequired(a => a.Job)
.WithMany(a => a.Assignments)
.HasForeignKey(a => a.JobId);
HasRequired(a => a.Checklist)
.WithOptional(a => a.Assignment);
HasMany(a => a.Images)
.WithRequired(a => a.Assignment)
.HasForeignKey(a => a.InspectionId);
}
}
The Checklist domain model has a ChecklistTemplate navigation property with the join:
HasMany(a => a.CheckLists)
.WithRequired(a => a.ChecklistTemplate)
.HasForeignKey(a => a.ChecklistTemplateId);
There is a one to one between Assignment and Checklist as seen in the Assignment entity configuration.
And yes, we are including the configuration in the DBContext.
Also, I looked at Entity Framework 6 creates Id column even though other primary key is defined and that doesn't seem to apply.
I dont have a satisfactory answer to that but I have had a lot of trouble with ef6. This is because there is a navigation which is not defined or wrongly defined. So ef6 creates it on-the-fly on proxy classes and you cry for hours. I hope you find out the problem soon.
And the navigation you stated is one-to-many. Be careful.

How can I include two relational properties of the same type?

I have an ApplicationUser model:
public class ApplicationUser : IdentityUser
{
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public List<Project> Projects { get; set; }
}
... and a Project model:
public class Project
{
public int Id { get; set; }
public int? ParentProjectId { get; set; }
[Required]
public string ProjectCreatorId { get; set; }
[Required]
public string ProjectOwnerId { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
public ApplicationUser ProjectCreator { get; set; }
public ApplicationUser ProjectOwner { get; set; }
public Project ParentProject { get; set; }
public virtual List<Project> ChildProjects { get; set; }
}
In OnModelCreating(), I tried this:
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Project>()
.HasMany(c => c.ChildProjects)
.WithOne(p => p.ParentProject)
.HasForeignKey(p => p.ParentProjectId);
modelBuilder.Entity<ApplicationUser>()
.HasMany(p => p.Projects)
.WithOne(o => o.ProjectOwner)
.HasForeignKey(po => po.ProjectOwnerId);
modelBuilder.Entity<ApplicationUser>()
.HasMany(p => p.Projects)
.WithOne(c => c.ProjectCreator)
.HasForeignKey(pc => pc.ProjectCreatorId);
But upon creating the database, I get
Cannot create a relationship between 'ApplicationUser.Projects' and 'Project.ProjectCreator', because there already is a relationship between 'ApplicationUser.Projects' and 'Project.ProjectOwner'. Navigation properties can only participate in a single relationship.
I tried the solutions to this old question, but wasn't able to make any of them work.
Is there another way I could keep track of both a Project's creator AND owner, and be able to .Include() them both in the queries?
Instead of different binding, use the single binding
modelBuilder.Entity<ApplicationUser>()
.HasMany(p => p.Projects)
.WithOne(o => o.ProjectOwner)
.HasForeignKey(po => po.ProjectOwnerId);
.WithOne(c => c.ProjectCreator)
.HasForeignKey(pc => pc.ProjectCreatorId);
I went for this solution:
As mentioned in the comments, ApplicationUser would need two List<Project>-properties:
public List<Project> CreatedProjects { get; set; }
public List<Project> OwnedProjects { get; set; }
Then, in OnModelCreating():
modelBuilder.Entity<Project>()
.HasOne(g => g.ProjectCreator)
.WithMany(t => t.CreatedProjects)
.HasForeignKey(t => t.ProjectCreatorId)
.HasPrincipalKey(t => t.Id);
modelBuilder.Entity<Project>()
.HasOne(g => g.ProjectOwner)
.WithMany(t => t.OwnedProjects)
.HasForeignKey(t => t.ProjectOwnerId).OnDelete(DeleteBehavior.NoAction)
.HasPrincipalKey(t => t.Id);
Now I'm able to include both creators and owners. :)

Trouble when trying to create a database with Entity Framework and migrations

I want to create database EF migrations via the developer command prompt for VS2015. When I try to use this command line:
dotnet ef migrations add v1
I get this error:
The property 'partCategoriess' cannot be added to the entity type
'PartCategoryPart' because a navigation property with the same name
already exists on entity type 'PartCategoryPart'.
Is anything wrong with the DbContext? I am trying to create a many-to-many table between categoryParts and parts.
public class ShoppingDbContext : IdentityDbContext<User>
{
public ShoppingDbContext(DbContextOptions options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
}
public DbSet<PartCategory> PartCategories { get; set; }
public DbSet<Part> Parts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<PartCategoryPart>()
.HasKey(t => new { t.partCategoriess, t.Part });
modelBuilder.Entity<PartCategoryPart>()
.HasOne(pt => pt.partCategoriess)
.WithMany(p => p.PartCategoryPart)
.HasForeignKey(pt => pt.PartCategoryId);
modelBuilder.Entity<PartCategoryPart>()
.HasOne(pt => pt.Part)
.WithMany(t => t.PartCategoryPart)
.HasForeignKey(pt => pt.PartId);
}
}
public class PartCategoryPart
{
public int Id { get; set; }
public int PartCategoryId { get; set; }
public PartCategory partCategoriess { get; set; }
public int PartId { get; set; }
public Part Part { get; set; }
}
public class PartCategory
{
public int PartCategoryId { get; set; }
public string Category { get; set; }
public List<ProductPartCategory> ProductPartCategories { get; set; }
public List<PartCategoryPart> PartCategoryPart { get; set; }
}
public class Part
{
public int PartId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public double? Price { get; set; }
public List<PartCategoryPart> PartCategoryPart { get; set; }
}
The problem here is how you are defining the primary key for the PartCategoryPart intermediate entity. You are using the navigation properties to define the PK and you have to use the FKs like this:
modelBuilder.Entity().HasKey(t => new { t.PartCategoryId, t.PartId});
Referring to my own assignment, here's how you properly create an entity. You did not define a key..
modelBuilder.Entity<Price>()
.HasKey(input => input.PriceId)
.HasName("PrimaryKey_Price_PriceId");
// Provide the properties of the PriceId column
modelBuilder.Entity<Price>()
.Property(input => input.PriceId)
.HasColumnName("PriceId")
.HasColumnType("int")
.UseSqlServerIdentityColumn()
.ValueGeneratedOnAdd()
.IsRequired();
//modelBuilder.Entity<Price>()
// .Property(input => input.MetricId)
// .HasColumnName("MetricId")
// .HasColumnType("int")
// .IsRequired();
modelBuilder.Entity<Price>()
.Property(input => input.Value)
.HasColumnName("Value")
.HasColumnType("DECIMAL(19,4)")
.IsRequired();
modelBuilder.Entity<Price>()
.Property(input => input.RRP)
.HasColumnName("RRP")
.HasColumnType("DECIMAL(19,4)")
.IsRequired(false);
modelBuilder.Entity<Price>()
.Property(input => input.CreatedAt)
.HasDefaultValueSql("GetDate()");
modelBuilder.Entity<Price>()
.Property(input => input.DeletedAt)
.IsRequired(false);
// Two sets of Many to One relationship between User and ApplicationUser entity (Start)
modelBuilder.Entity<Price>()
.HasOne(userClass => userClass.CreatedBy)
.WithMany()
.HasForeignKey(userClass => userClass.CreatedById)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity<Price>()
.HasOne(userClass => userClass.DeletedBy)
.WithMany()
.HasForeignKey(userClass => userClass.DeletedById)
.OnDelete(DeleteBehavior.Restrict);
Notice that after identifying which is the key you still need to declare its properties before you declare any relationships.
modelBuilder.Entity<Price>()
.HasKey(input => input.PriceId)
.HasName("PrimaryKey_Price_PriceId");
// Provide the properties of the PriceId column
modelBuilder.Entity<Price>()
.Property(input => input.PriceId)
.HasColumnName("PriceId")
.HasColumnType("int")
.UseSqlServerIdentityColumn()
.ValueGeneratedOnAdd()
.IsRequired();

Entity Framework 5 code first cannot get model to work

Tearing my hair out again on this one...using EF 5 Code First, building the model in code - compiles, so it is syntactically correct, but I get an exception when the code builds the model. Here is the entity class (I also have vaidation attributes, but have removed them here for readability):
[Table("USERS")]
public class User : IPEntity
{
#region Constructor (needs to initialize list objects for related entities)
public User()
{
this.Profiles = new List<Profile>();
this.ProfileDivs = new List<ProfileDiv>();
this.ProfileDepts = new List<ProfileDept>();
}
#endregion
#region Entity properties and validation attributes
[Key]
public long UserId { get; set; }
public long PclientId { get; set; }
public string UserName { get; set; }
public string UserDescription { get; set; }
public long? EmpId { get; set; }
public string MustChangePassword { get; set; }
public long? FailedLogins { get; set; }
public DateTime? LastLogin { get; set; }
public long? SequenceNumber { get; set; }
public string AllDivs { get; set; }
public string AllDepts { get; set; }
public string UserRole { get; set; }
public DateTime? BeginSupport { get; set; }
public DateTime? EndSupport { get; set; }
public string OneTimeAccess { get; set; }
public long? ClonedFromUser { get; set; }
public string Email { get; set; }
public string ResetEmail { get; set; }
public DateTime? ResetTimeout { get; set; }
public long? ChallengeFailures { get; set; }
public string PermUserRole { get; set; }
public DateTime? PasswordChangedDate { get; set; }
public virtual ICollection<Profile> Profiles { get; set; }
public virtual ICollection<ProfileDiv> ProfileDivs { get; set; }
public virtual ICollection<ProfileDept> ProfileDepts { get; set; }
public virtual WorkSession WorkSession { get; set; }
}
The model builder class is:
public class User_Map : EntityTypeConfiguration<User>
{
public User_Map()
{
this.ToTable("USERS");
this.HasKey(t => new { t.UserId });
this.Property(t => t.UserId)
.HasColumnName("USER_ID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)
.IsRequired();
this.Property(t => t.UserName)
.HasColumnName("USERNAME")
.IsRequired()
.HasMaxLength(25);
this.Property(t => t.PclientId)
.HasColumnName("PCLIENT_ID");
this.Property(t => t.EmpId)
.HasColumnName("EMP_ID");
this.Property(t => t.MustChangePassword)
.HasColumnName("MUST_CHANGE_PASSWORD")
.HasMaxLength(1);
this.Property(t => t.UserDescription)
.HasColumnName("USER_DESCRIPTION")
.HasMaxLength(80);
this.Property(t => t.FailedLogins)
.HasColumnName("FAILED_LOGINS");
this.Property(t => t.LastLogin)
.HasColumnName("LAST_LOGIN");
this.Property(t => t.SequenceNumber)
.HasColumnName("SEQUENCE_NUMBER");
this.Property(t => t.AllDivs)
.HasColumnName("ALL_DIVS")
.HasMaxLength(1);
this.Property(t => t.AllDepts)
.HasColumnName("ALL_DEPTS")
.HasMaxLength(1);
this.Property(t => t.UserRole)
.HasColumnName("USER_ROLE")
.HasMaxLength(2);
this.Property(t => t.BeginSupport)
.HasColumnName("BEGIN_SUPPORT");
this.Property(t => t.EndSupport)
.HasColumnName("END_SUPPORT");
this.Property(t => t.OneTimeAccess)
.HasColumnName("ONE_TIME_ACCESS")
.HasMaxLength(1);
this.Property(t => t.ClonedFromUser)
.HasColumnName("CLONED_FROM_USER");
this.Property(t => t.Email)
.HasColumnName("EMAIL")
.HasMaxLength(60);
this.Property(t => t.ResetEmail)
.HasColumnName("RESET_EMAIL")
.HasMaxLength(60);
this.Property(t => t.ResetTimeout)
.HasColumnName("RESET_TIMEOUT");
this.Property(t => t.ChallengeFailures)
.HasColumnName("CHALLENGE_FAILURES");
this.Property(t => t.PermUserRole)
.HasColumnName("PERM_USER_ROLE")
.HasMaxLength(2);
this.Property(t => t.PasswordChangedDate)
.HasColumnName("PASSWORD_CHANGED_DATE");
this.HasOptional(t => t.WorkSession)
.WithRequired(t => t.User);
// TODO: This is syntactically correct but model blows up!
this.HasMany(t => t.Profiles)
.WithRequired(t => t.User)
.HasForeignKey(t => t.UserId);
}
}
When the model builder class' constructor executes, I get the following exception thrown on the line above (after the comment):
The expression 't => t.User' is not a valid property expression.
The expression should represent a property: C#: 't => t.MyProperty'
VB.Net: 'Function(t) t.MyProperty'.
The Profiles entity is very simple:
[Table("PROFILE")]
public class Profile : IPEntity
{
[Key, Column(Order = 0)]
[ForeignKey("UserId")]
public long UserId { get; set; }
[Key, Column(Order = 1)]
public string FunctionalArea { get; set; }
public int RightsId { get; set; }
public User User;
}
I have been beating on this for two or three days, if anyone can spot my mistake, I would be MOST appreciative!
Thanks,
Peter
UPDATE: I found one bone-headed mistake by reading this post, since I had declared something as a field and not a property...but now I get a different exception which I do not understand:
The navigation property 'UserId' is not a declared property on type 'Profile'.
Verify that it has not been explicitly excluded from the model and that
it is a valid navigation property.
This has me confused as UserId IS a declared property on Profile...?
SECOND UPDATE:
I understand the exception but (since there is no inner exception detail) cannot determine where it is coming from. I changed the User_map class to include:
this.HasMany(t => t.Profiles)
.WithRequired(t => t.User)
.HasForeignKey(t => t.UserId)
.WillCascadeOnDelete(false);
and the Profile_map class to include:
this.HasRequired(t => t.User)
.WithMany()
.HasForeignKey(t => t.UserId)
.WillCascadeOnDelete(false);
Since I have to work with the existing database, I am stuck with the property "UserId" being a foreign key in both tables (in User table it is foreign key for Profiles table, in Profiles table it is foreign key for User table.) I added the .WillCascadeOnDelete(false) to both in case there was some kind of circularity problem. Like I said, I cannot determine which map is blowing things up, the calls to both constructors pass without exception, it is only when the override for OnModelCreating in the context exits that the exception is thrown. Here is the override:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var mbProfile = new Profile_map();
modelBuilder.Configurations.Add(mbProfile);
var mbUser = new User_Map();
modelBuilder.Configurations.Add(mbUser);
base.OnModelCreating(modelBuilder);
}
I know I'm still an EF newbie, but I cannot find the problem (well, haven't yet anyway...)
Thanks again.
public User User;
should be a property instead of a field - like all the others :)
public User User { get; set; }
With virtual preferably (to allow lazy loading), because you have marked all your navigation properties as virtual.
Edit about the UPDATE
The exception talks about a navigation property UserId and complains that it is not a "valid navigation property". Indeed it isn't a valid navigation property. The exception indicates that you possibly have used UserId (instead of User) in the WithRequired method. You should take a closer look at that.
Peter, with regard to your issue with the two "UserId" columns, you said that they were both foreign keys. I don't think you are correct. The User.UserId is marked with [Key] and it is the only one in the User class marked that way. It must be the primary id for the User table. On the Profile class, you have both UserId and FunctionalArea marked with [Key]. This means that the Profile table has a joint primary key, one of which is the foreign key to the User table's UserId column.
That design is perfectly fine. However, in order to have a relationship between User and Profile records where the Profile record is the parent, you would have to have TWO columns on your User table that reference the Profile table's two primary keys, and NEITHER of those columns could be the UserId column of the User table, otherwise you would have a circular dependency with no way of creating either record.
Bottom line is, you don't have two relationships between the User and Profile tables, just one. So delete the following block from your Profile_map class:
this.HasRequired(t => t.User)
.WithMany()
.HasForeignKey(t => t.UserId)
.WillCascadeOnDelete(false);
That should fix it right up! ;)

Categories