I have a problem with Entity Framework, I think I have a problem defining the one to many mapping, but I can't seem to find it.
When I try to save my changes and add my info to the database I get the following error:
Invalid object name 'Results1'
With Results being the name of one of my tables, for some reasons it's adding the 1 at the end.
I have a Results table where I need to store an Id and several other information regarding results of a test, then I have a Reasons table where I need to store several reasons for each Result.Id.
This is how I defined the Reasons class:
public class Reasons
{
public int Id { get; set; }
public int ResultId { get; set; }
public string Description { get; set; }
public Results Results { get; set; }
}
Then I have the Results class:
public class Results
{
public int Id { get; set; }
//Other properties
public ICollection<Reasons> Reasons { get; set; }
}
This is my Reasons configuration:
configurator.
Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
configurator
.HasRequired<Results>(s => s.Results)
.WithMany(g => g.Reasons)
.HasForeignKey<int>(s => s.IdResults);
Solved: the only problem was that the "Reasons" and the "Results" class did not completely match the data model. Once that was repaired the problem disappeared.
Rename your foreign key in Reasons class from ResultId to ResultsId or explicitly use [ForeignKey("Results")] attribute above it. From here:
EF makes a property as foreign key property when its name matches with
the primary key property of a related entity
In your case it should be:
// Foreign key for Results
public int ResultsId { get; set; }
// Navigation property
public Results Results { get; set; }
Remove your configuration instructions. There is no need to use fluent api to configure your database scheme since entity framework will do it by self. Here are examples how to configure one to many relations via code first approach
As was answered in comments it is a good practice to use singular name for a model in order to use plural form for navigational properties.
Related
I'm having trouble with model first in entity framework 6, .net 4.7, visual studio 2017...
I'm trying to add a many to 0...1 with foreign key between two tables and when I try to validate the model I get an error saying the foreign key field in the table is not mapped. Furthermore, I cannot even add new entities to the model as I get an error on validation saying the entity is not mapped. What has it done to get itself into this state? I have barely used it to do anything.
What do I do to get it to do things without these errors? I know it's because it hasn't mapped things but it should do this automatically. The whole thing seems sloppy considering it's version 6.
Should I switch to Database first?
Thankyou.
for set relation many to 0...1 you must
1) Create models and add related entities in models
public class MainModel
{
public MainModel()
{
ChildModels= new HashSet<ChildModel>();
}
public int Id { get; set; }
public virtual ICollection<ChildModel> ChildModels{ get; set; }
}
public class ChildModel
{
public int Id { get; set; }
public int? MainModelId { get; set; }
public MainModel MainModel { get; set; }
}
2) Set relation in Context class by FluentApi
modelBuilder.Entity<MainModel>()
.HasMany(mm => mm.ChildModels)
.WithOptional(cm => cm.MainModel )
.HasForeignKey(cm => cm.MainModelId );
In one of this steps you may make mistake.
Database first is old approach and i don't advice you to use it.
First off, I'm new to the Entity Framework and am migrating an existing project from a database framework that I wrote myself so I have a fair amount of flexibility in the solution I choose.
From what I've researched so far everything appears to be set up correctly. However, when my database is constructed, the table for a helper class I wrote has no columns in it (outside of its primary key). The most simplified version of the classes are included below with their relationships defined in the fluent API.
Classes
public class Concept
{
public long ID { get; set; }
[Index(IsUnique = true), MaxLength(255)]
public string Name { get; set; }
}
public class Tag
{
public long ID { get; set; }
public virtual Content Subject { get; set; }
public virtual Concept Concept { get; set; }
}
public class Helper
{
public long ID { get; set; }
public virtual Content Subject { get; set; }
public virtual List<Tag> Instances { get; set; }
// Helper functionality
}
public class Content
{
public long ID { get; set; }
public virtual Helper Helper { get; set; }
public Content() { Helper = new Helper() { Subject = this }; }
}
Context
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Tag>()
.HasRequired(t => t.Concept);
modelBuilder.Entity<Tag>()
.HasRequired(t => t.Subject);
modelBuilder.Entity<Helper>()
.HasRequired(t => t.Subject)
.WithRequiredDependent(c => c.Helper);
modelBuilder.Entity<Helper>()
.HasMany(t => t.Instances);
modelBuilder.Entity<Content>()
.HasRequired(c => c.Helper)
.WithRequiredPrincipal();
base.OnModelCreating(modelBuilder);
}
Program.cs
static void Main(string[] args)
{
Content content = null;
using (var context = new Context())
{
content = context.Content.Find(1);
if (content == null)
{
content = new Content();
context.Content.Add(content);
context.Helper.Add(content.Helper);
context.SaveChanges();
}
}
}
It's also worth mentioning that when the data is saved, the Helper is assigned an ID but on loading the parent class (Content) the second time around, the Helper is not lazy loaded as I would expect from the 'virtual' keyword. I suspect that this is caused by the same issue causing the absence of data in the table.
I have tried both the data annotation and fluent API approaches that EF provides but it seems that there is something fundamental that I am misunderstanding. I would like to retain this helper class as it helps organize the code far better.
As I have spent a fair amount of time researching these relationships / APIs, and scouring Google / SO without found anything to solve this issue in particular any help would be greatly appreciated!
Updated: Solution
Thanks to a question in the comments, I realized that I was expecting to see the keys of a many-to-many relationship in the tables for the entity types themselves (i.e. in the Helpers table). However, in a many-to-many relationship, the keys will always be placed in a separate table (concatenation of type names) which was not being previously created.
By adding '.WithMany();' to the Helper section of the OnModelCreating function as below
modelBuilder.Entity<Helper>()
.HasMany(t => t.Instances)
.WithMany();
the many-to-many relationship became properly defined and the HelperTags table generated as expected. This is due to the fact that the many-to-many relationship is one way (Helpers always refer to Tags, Tags never refer to Helpers). This is also why the 'WithMany' does not have any arguments (since no Helper properties exist in the Tag class). Fixing this simple oversight solved the problem!
You are probably working harder than you need to in the on ModelCreate. You should probably redesign your classes use Identifiers, like this:
public class Tag
{
public long Id { get; set; }
public long SubjectId { get; set; }
public long ConceptId { get; set; }
public virtual Content Subject { get; set; }
public virtual Concept Concept { get; set; }
}
You need to keep the ID names the EXACT same as the object names + Id and EF will magically link everything up. If you don't want them required then make the id nullable (C# 6 == long? SubjectId).
Also, I have changed the ID -> Id; I have no idea if this matters. At one point I remember having to do that to get things working (it was YEARS ago) and I have been doing it that way ever since.
Consider reading:
Entity Framework Code First Conventions
relationship Convention
In addition to navigation properties, we recommend that you include
foreign key properties on the types that represent dependent objects.
Any property with the same data type as the principal primary key
property and with a name that follows one of the following formats
represents a foreign key for the relationship:
<navigation property name><principal primary key property name>
<principal class name><primary key property name>
<principal primary key property name>
If multiple matches are found then precedence is given in the order
listed above.
Foreign key detection is not case sensitive.
Sample Code from MSDN:
In the following example the navigation properties and a foreign key are used to define the relationship between the Department and Course classes.
public class Department
{
// Primary key
public int DepartmentID { get; set; }
public string Name { get; set; }
// Navigation property
public virtual ICollection<Course> Courses { get; set; }
}
public class Course
{
// Primary key
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
// Foreign key
public int DepartmentID { get; set; }
// Navigation properties
public virtual Department Department { get; set; }
}
tl;dr Do I need to have a foreign key id field as a property in the related class with EF code-first?
Following ScottGu's advice, i have created a model to reflect an existing database. Two of the tables in the db are: Project and ProjectType with a foreign key relationship. Each Project has a ProjectType.
I have added the necessary virtual fields to the model classes to reflect the relationship:
public class Project {
public int ProjectID { get; set; }
public string ProjectName { get; set; }
public DateTime CreationDate { get; set; }
...
public virtual ProjectType ProjectType {get; set; }
...
}
public class ProjectType {
public int ProjectTypeID { get; set; }
...
public virtual ICollection<Project> Projects { get; set;}
...
}
According to Scott (as shown in the image below), there is no need for the actual (foreign key) ID field to be exposed in the dependent class, ie, I don't need a public int ProjectTypeID { get; set; } property in the Project class.
However, when I try a call to retrieve the data, I hit an EntityCommandExecutionException with an InnerException of: Invalid column name 'ProjectType_ProjectTypeID'
Initial googling suggested adding a [ForeignKey] annotation to the ProjectType property. I tried both [ForeignKey("ProjectType")] and [ForeignKey("ProjectTypeID")] but neither worked.
Further googling suggested using FluentAPI with a call to:
modelBuilder.Entity<Project>().HasRequired<ProjectType>(p => p.ProjectType)
.WithMany(pt => pt.Projects)
in an OnModelCreating method, but this falls over with the same Invalid column name error.
So, do I need to have the ProjectTypeID field as a property in the Project class? If not, how do I tell EF to use the ProjectTypeID as the foreign key?
What is the foreign key column name in the existing database? You don't need to add a foreign key field but you do need to configure your modelBuilder so that foreign key names match.
modelBuilder.Entity<Project>()
.HasRequired<ProjectType>(p => p.ProjectType)
.WithMany(pt => pt.Projects)
.Map(p => p.MapKey("FK_NAME_IN_EXISTING_DB"));
You can also choose the option to have EF generate code first from database.
I have 3 tables where Property has a foreign key to Dependent and Dependent has a foreign key to Main, causing a One-to-Many relationship for each of the tables. However I am only interested in the most recent record in Dependent and its Property records, thus i created a view v_Dependent which returns the most recent Dependant record grouped by MainId. This will enable a One-to-One relationship between Main and Dependant which is what I'm after, works with the code below.
I am eager loading all when loading Main objects, however after i switched to the view I may no longer eager load the records in the Properties collection of Dependent. The reason for this is that to map the view into a One-to-One relationship I had to add MainId to the composite key for Dependent. Now the foreign key from Property would have to contain the MainId as well to be able to load the collection, however I do not have MainId in the database table, nor do I want to.
My question is, do I have to create a view for Property as well to include the MainId and add this to the entity composite foreign key, or is there anything else I can do to map this using fluent API? Another option I'm currently using is explicitly loading the Property collection in my repository, however I was hoping fluent API could handle this for me. The commented out line is the config which worked for the whole graph while I treated the Dependent as a collection on Main. I am using the entities read only, so dont have to worry about storing back.
public class Main
{
public int MainId { get; set; }
public Dependent Dependent { get; set; }
}
public class Dependent
{
public int DependentId { get; set; }
public int MainId { get; set; }
public Main Main { get; set; }
public ICollection<Property> Properties { get; set; }
}
public class Property
{
public int PropertyId { get; set; }
public int DependentId { get; set; }
public Dependent Dependent { get; set; }
}
public class SomeContext : DbContext
{
public DbSet<Main> Mains { get; set; }
public DbSet<Dependent> Dependents { get; set; }
public DbSet<Property> Properties { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Main>().ToTable("Main").HasKey(m => m.MainId);
//modelBuilder.Entity<Dependent>().ToTable("Dependent").HasKey(d => d.DependentId).HasRequired(d => d.Main).WithMany(m => m.Dependents).HasForeignKey(d => d.MainId);
modelBuilder.Entity<Dependent>().ToTable("v_Dependent").HasKey(d => new {d.DependentId, d.MainId}).HasRequired(d => d.Main).WithOptional(m => m.Dependent);
modelBuilder.Entity<Property>().ToTable("Property").HasKey(p => p.PropertyId).HasRequired(p => p.Dependent).WithMany(d => d.Properties).HasForeignKey(p => p.DependentId);
base.OnModelCreating(modelBuilder);
}
}
After alot of digging I found out that the underlying issue is that entity framework is unable to map a One to Zero or One relationship using a foreign key instead of primary key. See https://entityframework.codeplex.com/workitem/299
As a result I had to choose between changing the primary key of Dependent (which is currently a view and thus I could create an indexed view with all the limitations of such, but I have a subquery I cannot get rid of) or load the properties seperately. I chose the latter and changed the applcation to no longer have a navigation property and loading the properties when needed.
I have two classes defined as such:
public class Questionnaire
{
public int QuestionnaireID { get; set; }
public string Title { get; set; }
public bool Active { get; set; }
public virtual ICollection<Question> Questions { get; set; }
public virtual ICollection<Vendor> Vendors { get; set; }
}
public class Vendor
{
public int VendorID { get; set; }
public string VendorName { get; set; }
public virtual ICollection<Questionnaire> OpenQuestionnaires { get; set; }
public virtual ICollection<Questionnaire> SubmittedQuestionnaires { get; set; }
public virtual ICollection<QuestionnaireUser> QuestionnaireUsers { get; set; }
}
I beleive this is the correct way to establish a many-to-many relationship between these classes, and when the project is built, I would expect three tables to be created.
However, when I attempt to to relate one Questionnaire to two different Vendors, I receive the following error when attempting to save the changes (context.SaveChanges()):
*Multiplicity constraint violated. The role 'Vendor_OpenQuestionnaires_Source' of the relationship 'QuestionnaireApp.Models.Vendor_OpenQuestionnaires' has multiplicity 1 or 0..1.*
If I assign a Questionnaire to only one Vendor, save the changes and then assign it to another and again save changes I no longer get the error; however the Questionaire is then related only to the last Vendor to which it was assigned, indicating that (at best) there is a one-to-many relationship being created.
I'm hoping that there is something wrong with the way I'm declaring the many-to-many relationship between these classes, or perhaps there is something I need to add to the context class to "encourage" the relationsip, but perhaps many-to-many relationships like this are not supported, or cannot be created using "Code First"?
Thank you for your time,
Jason
If you don't have any Fluent API code your expected mapping relies on EF Code First conventions. The convention which you expect to kick in here is the AssociationInverseDiscoveryConvention. Now if you look in Intellisense (and probably also documentation) it says about this convention:
Convention to detect navigation properties to be inverses of each
other when only one pair of navigation properties exists between the
related types.
Now, that's the problem: You don't have only "one pair" of navigation properties between Questionnaire and Vendor. You have two collections in Vendor refering to Questionnaire and one collection in Questionnaire refering to Vendor. The result is that this convention doesn't get applied and EF maps actually three one-to-many relationships with only one end exposed as navigation property in the model.
Moreover the mapping you want to achieve is not possible with your model: You cannot map the one end Questionnaire.Vendors to the two ends Vendor.OpenQuestionnaires and Vendor.SubmittedQuestionnaires.
One workaround is to change your model the following way:
public class Vendor
{
public int VendorID { get; set; }
public string VendorName { get; set; }
[NotMapped]
public IEnumerable<Questionnaire> OpenQuestionnaires
{
get { return Questionnaires.Where(q => q.IsActive); }
}
[NotMapped]
public IEnumerable<Questionnaire> SubmittedQuestionnaires
{
get { return Questionnaires.Where(q => !q.IsActive); }
}
public virtual ICollection<Questionnaire> Questionnaires { get; set; }
public virtual ICollection<QuestionnaireUser> QuestionnaireUsers { get; set; }
}
Now Vendor.Questionnaires is mapped to Questionnaire.Vendors (AssociationInverseDiscoveryConvention should detect this) and the helper properties OpenQuestionnaires and SubmittedQuestionnaires allow you to pull out the selected items. (I'm not sure if IsActive is your distinguishing flag. Otherwise you have to introduce some new flag.)
The [NotMapped] attribute is just here to make it explicite. It is probably not necessary because EF won't map IEnumerable collections and readonly properties with only a getter anyway.
Go figure, after an hour or so of searching, I go and find the exact answer 30 seconds after I post my question.
The solution was to add the following to the context class:
modelBuilder.Entity<Vendor>()
.HasMany<Questionnaire>(x => x.OpenQuestionnaires)
.WithMany(x => x.Vendors)
.Map(x =>
{
x.MapLeftKey("vID");
x.MapRightKey("qID");
x.ToTable("VendorQuestionnaires");
});
I found the answer by reading this Stack Overflow post: EF Code First Many-to-Many not working