I am creating a ASP.NET web API project (database first) and it pulls the data from the MSSQL database (read-only access). Database have several tables but there is no primary/secondary keys (we cannot change it). I have set up of one-to-many relations without any problem, but when it comes to the many-to-many, I had to use link tables for holding keys from both side.
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
public IList<StudentCourse> StudentCourses { get; set; }
}
public class Course
{
public int CourseId { get; set; }
public string CourseName { get; set; }
public string Description { get; set; }
public IList<StudentCourse> StudentCourses { get; set; }
}
Link table:
public class StudentCourse
{
public int StudentId { get; set; }
public Student Student { get; set; }
public int CourseId { get; set; }
public Course Course { get; set; }
}
Because link table is not present in the database I am getting error of "Data.SqlClient.SqlException: 'Invalid object name 'StudentCourse' ".
public class SchoolContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=.\\SQLEXPRESS;Database=EFCore-SchoolDB;Trusted_Connection=True");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<StudentCourse>().HasKey(sc => new { sc.StudentId, sc.CourseId });
}
public DbSet<Student> Students { get; set; }
public DbSet<Course> Courses { get; set; }
public DbSet<StudentCourse> StudentCourses { get; set; }
Relationships:
modelBuilder.Entity<StudentCourse>().HasKey(sc => new { sc.SId, sc.CId });
modelBuilder.Entity<StudentCourse>()
.HasOne<Student>(sc => sc.Student)
.WithMany(s => s.StudentCourses)
.HasForeignKey(sc => sc.SId);
modelBuilder.Entity<StudentCourse>()
.HasOne<Course>(sc => sc.Course)
.WithMany(s => s.StudentCourses)
.HasForeignKey(sc => sc.CId);
I considered Joining tables on these keys but it seems not efficient way of handling relationships and getting related records. What work arounds would you suggest?
Entity Framework is an Object-to-Relational Mapper, Mapper being the key term here. In order to have a relationship between objects to map, there must be a relationship between those entities in the relational database.
Think of it this way, if there is a relationship between students and courses, how is that relationship represented within your database? If I asked you to write two SQL queries against that database, how would you return the following data?
List all students for a specific Course.
List all courses for a specific Student.
You cannot do that with just a Course and a Student table. If there is no linking table then you either have a 1-to-many relationship one way or the other, or the database handles it in a non-relational way. (Such as Student containing a string field with a comma-delimited list of Course IDs) In which case, EF will be of little help.
If the database does not support recording a mapping between students and their courses where you can query how one student can participate in many courses, while each course can have many students participating, then EF cannot be configured to somehow auto-magically read and persist such a relationship. A many-to-many table must exist within the database or such a relationship cannot exist. With EF6 and EF Core 5+ you may read that EF can handle many-to-many relationships without a linking entity, which is true, but that does not mean without a linking table. The table must exist, but you don't need to define a StudentCourse (or CourseStudent) entity.
Instead of:
public IList<StudentCourse> StudentCourses { get; set; }
in both Student and Course, Student can have:
public IList<Course> Courses { get; set; }
while Course has:
public IList<Student> Students { get; set; }
This still maps through a linking table, and provided that relationship just consists of a StudentId and CourseId in the table with no other columns that need to be mapped/configured, EF can manage that relationship and table entirely behind the scenes.
If there is a linking table, just not named what you'd expect: You can call the entity whatever you want and use configuration via attributes, DbContext.OnModelCreating(ModelBuilder), or EntityTypeConfiguration to map that entity and properties to the existing table and columns, however they might be named. But such a table must exist to support that relationship.
Related
Referencing from the #Ogglas answer of this post,
I would like to ask if it is normal for EF to generate another table?
If the additional table should not be there, then what am I doing wrong here? Please enlighten me. TIA!
Sample code:
public class Aggregate
{
public Aggregate()
{
Episodes = new HashSet<Episode>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }
...
public virtual ICollection<Episode> Episodes { get; set; }
}
public class Episode
{
public Episode()
{
Aggregates = new HashSet<Aggregate>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }
...
public virtual ICollection<Aggregate> Aggregates { get; set; }
}
public class EpisodeAggregate
{
[Key]
[Column(Order = 1)]
[ForeignKey("Episode")]
public Guid EpisodeId { get; set; }
[Key]
[Column(Order = 2)]
[ForeignKey("Aggregate")]
public Guid AggregateId { get; set; }
public virtual Episode Episode { get; set; }
public virtual Aggregate Aggregate { get; set; }
public DateTime Timestamp { get; set; }
}
In my DbContext.cs:
public DbSet<EpisodeAggregate> EpisodeAggregates { get; set; }
You are right. In a relational database, a many-to-many relation is solved using a junction table.
For a standard many-to-many relationship, you don't need to mention this junction table; entity framework recognizes the many-to-many by your use of the virtual ICollection<...> on both sides of the many-to-many relation, and will automatically create the tables for you.
To test my database theories and entity framework, I quite often use a simple database with Schools, Students and Teachers. One-to-many for School-Student and School-Teacher and many-to-many for Teacher-Student. I always see that the Teacher-Student junction table is created automatically, without ever having to mention it.
However!
Your junction table is not standard. A standard junction table has only two columns: the EpisodeId and the AggregateId. It doesn't even have an extra primary key. The combination [EpisodeId, AggregateId] is already unique and can be used as a primary key.
You have in table EpisodeAggregate an extra column: TimeStamp. Apparently you want to know when an Episode and an Aggregate got related.
"Give me the TimeStamp when Episode[4] got related with Aggregate[7]"
This makes that this table is not a standard junction table. There is no many-to-many relation between Episodes and Aggregates. You made a one-to-many relation between Episode and its Relations with the Aggregates, and similarly a one-to-many relation between Aggregates and its Relations with the Episodes.
This makes that you have to change your many-to-many into one-to-many:
class Episode
{
public Guid Id { get; set; }
// every Episode has zero or more Relations with Aggregates (one-to-many)
public virtual ICollection<EpisodeAggregateRelation> EpisodeAggregateRelations { get; set; }
...
}
class Aggregate
{
public Guid Id { get; set; }
// every Episode has zero or more Relations with Episodes(one-to-many)
public virtual ICollection<EpisodeAggregateRelation> EpisodeAggregateRelations { get; set; }
...
}
class EpisodeAggregateRelation
{
// Every Relation is the Relation between one Episode and one Aggregate
// using foreign key:
public Guid EpisodeId { get; set; }
public Guid AggregateId { get; set; }
public virtual Episode Episode { get; set; }
public virtual Aggregate Aggregate { get; set; }
public DateTime Timestamp { get; set; }
}
If you are certain the there will always be at utmost one relation between an Episode and an Aggregate, you can use the combination [EpisodeId, AggregateId] as a primary key. If you think these two might have several relations, you need to add a separate primary key.
I often use my classes in different databases, hence I don't like attributes, I solve it in fluent API in OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Episode>()
.HasKey(episode => episode.Id)
// define the one-to-many with EpisodeAggregateRelations:
.HasMany(episode => episode.EpisodeAggregateRelations)
.WithRequired(relation => relation.Episode)
.HasForeignKey(relation => relation.EpisodeId);
modelBuilder.Entity<Aggregate>()
.HasKey(aggregate => aggregate.Id)
// define the one-to-many with EpisodeAggregateRelations:
.HasMany(aggregate => aggregate .EpisodeAggregateRelations)
.WithRequired(relation => relation.Aggregate)
.HasForeignKey(relation => relation.aggregateId);
The above is not needed!
Because you followed the entity framework code first conventions, you can omit these two statements. Entity framework will recognize the primary key and the one-to-many relation. Only if you want to deviate from the conventions, like a non-standard table name, or if you want to define the column order:
modelBuilder.Entity<Episode>()
.ToTable("MySpecialTableName")
.Property(episode => episode.Date)
.HasColumnName("FirstBroadcastDate")
.HasColumnOrder(3)
.HasColumnType("datetime2");
But again: you followed the conventions, all those attributes like Key, ForeignKey, DatabaseGenerated are not needed. And the column order: who cares? Let your database management system decide about the most optimum column order.
My advice would be: try to experiment: leave out this fluent API and check whether your unit tests still pass. Checked in five minutes.
The EpisodeAggregateRelation has something non-standard: it has a composite primary key. Hence you need to define this. See Configuring a composite primary key
modelBuilder.Entity<EpisodeAggregateRelation>()
.HasKey(relation => new
{
relation.EpisodId,
relation.AggregateId
});
If you already defined the one-to-many in Episodes and Aggregates, or if that was not needed because of the conventions, you don't have to mention this relation here again.
If you want, you can put the one-to-many in the fluent API part of EpisodeAggregateRelation, instead of in the fluent API part of Episode / Aggregate:
// every EpisodeAggregateRelation has one Episode, using foreign key
modelBuilder.Entity<EpisodeAggregateRelation>()
.HasRequired(relation => relation.Episode(
.WithMany(episode => episode.EpisodeAggregateRelations)
.HasForeignKey(relation => relation.EpisodeId);
// similar for Aggregate
One final tip
Don't create a HashSet in the constructor. It is a waste of processing power if you fetch data: you create the HashSet, and it is immediately replaced by the ICollection<...> that entity framework creates.
If you don't believe me: just try it out, and see that your unit tests pass, with the possible exception of the unit test that checks for an existing ICollection<...>
I've designed a database, paying a lot of attention to normalization.
Here's a piece of it:
First of all, If you notice any issues with this design, feel free to let me know.
The goal is to have companies, each of which have some departments.
Departments can be shared between companies.
As in:
Company 1 can have Department 1, 2 and 3.
Company 2 can have Department 1, 5, 8 and 9.
The BusinessUnits will have access to departments.
But it depends on the company to which a department is linked.
BusinessUnit 1 may have permission to access Department 1 of Company 1, but should not be able to access Department 1 of Company 2.
The CompanyDepartment config table is pretty obvious.
It links a Company to (possibly) multiple departments.
The CompanyDepartmentBusinessUnit config table is used to link BusinessUnits to Departments of a Company.
In this table, the CompanyId and DepartmentId form a composite Foreign Key to the primary key of CompanyDepartment (which is: CompanyId and DepartmentId as well).
I'm using a Database-First approach in Entity Framework.
For the simple junction tables, I've overwritten the OnModelCreating method in my DbContext.
An example of how I did this:
My question now is: how do I do this for the CompanyDepartmentBusinessUnit relation?
Say that my user chose to see the departments of Company 1.
I want to filter all the Departments that are linked to Company 1 but are also visible to the BusinessUnit in which the user resides (for instance Business Unit 2).
Thank you in advance and enjoy your holidays!
EF allows you to use implicit junction table only if (1) it has no additional columns and (2) if it's not referenced by other entity different than the two ends of the many-to-many relationships.
CompanyDepartment satisfies the condition (1), but not (2) because it's referenced from CompanyDepartmentBusinessUnit, hence you need to use explcit entity with two one-to-many relationships.
Once you do that, it can be seen that now CompanyDepartmentBusinessUnit satisfies both conditions, hence can be modelled with implicit junction table for BusinessUnit and CompanyDepartment.
With that being said, the final model would be something like this:
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<CompanyDepartment> DepartmentLinks { get; set; }
}
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<CompanyDepartment> CompanyLinks { get; set; }
}
public class BusinessUnit
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsPersonal { get; set; }
public ICollection<CompanyDepartment> CompanyDepartments { get; set; }
}
public class CompanyDepartment
{
public int CompanyId { get; set; }
public int DepartmentId { get; set; }
public Company Company { get; set; }
public Department Department { get; set; }
public ICollection<BusinessUnit> BusinessUnits { get; set; }
}
and taking into account the default EF conventions, with the following minimal fluent configuration:
modelBuilder.Entity<Company>().ToTable("Company");
modelBuilder.Entity<Department>().ToTable("Department");
modelBuilder.Entity<BusinessUnit>().ToTable("BusinessUnit");
modelBuilder.Entity<CompanyDepartment>().ToTable("CompanyDepartment");
modelBuilder.Entity<CompanyDepartment>()
.HasKey(e => new { e.CompanyId, e.DepartmentId });
modelBuilder.Entity<CompanyDepartment>()
.HasMany(e => e.BusinessUnits)
.WithMany(e => e.CompanyDepartments)
.Map(m => m
.MapLeftKey("CompanyId", "DepartmentId")
.MapRightKey("BusinessUnitId")
.ToTable("CompanyDepartmentBusinessUnit")
);
I am building ASP.NET MVC 5 application. I am using Entity Framework 6.1, code first approach to generate a database. I have a many-to-many relationship between Product and Category.
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
// navigation
public virtual ICollection<Category> Categories { get; set; }
}
public class Category
{
public long Id { get; set; }
public string Name { get; set; }
// navigation
public virtual ICollection<Product> Products { get; set; }
}
In the Dbcontext class I override OnModelCreating method to create table for many-to-many relationship as below:
modelBuilder.Entity<Product>().HasMany<Category>(s => s.Categories).WithMany(c => c.Products)
.Map(cs =>
{
cs.MapLeftKey("ProductId");
cs.MapRightKey("CategoryId");
cs.ToTable("ProductCategories");
});
The table comes out as joining the two foreign keys. How do I add an Id (as primary key) to this junction table?
ProductCategories
- Id // add id as primary key
- ProductId
- CategoryId
Let me expand #bubi's answer:
By default, when you define many-to-many relationship (using attributes or FluentAPI), EF creates it (add additional table to DB) and allows you to add many products to a category and many categories to a product. But it doesn't allow you to access the linking table rows as entities.
If you need such feature, for example you what to manage these links some way like mark them as "deleted" or set a "priority", you need to:
Create new Entity (ProductCategoryLink)
Add it to your Context as another DbSet
Update relations in Product and Category entities accordingly.
For you it could like:
Entities
public class Product
{
[Key]
public long ProductId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
[InverseProperty("Product")]
public ICollection<ProductCategoryLink> CategoriesLinks { get; set; }
}
public class Category
{
[Key]
public long CategoryId { get; set; }
public string Name { get; set; }
[InverseProperty("Category")]
public ICollection<ProductCategoryLink> ProductsLinks { get; set; }
}
public class ProductCategoryLink
{
[Key]
[Column(Order=0)]
[ForeignKey("Product")]
public long ProductId { get; set; }
public Product Product { get; set; }
[Key]
[Column(Order=1)]
[ForeignKey("Category")]
public long CategoryId { get; set; }
public Category Category { get; set; }
}
I used attribute-way to define relations as I prefer this approach more. But you can easily replace it by a FluentAPI with two one-to-many relations:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Product to Links one-to-many
modelBuilder.Entity<ProductCategoryLink>()
.HasRequired<Product>(pcl => pcl.Product)
.WithMany(s => s.CategoriesLinks)
.HasForeignKey(s => s.ProductId);
// Categories to Links one-to-many
modelBuilder.Entity<ProductCategoryLink>()
.HasRequired<Category>(pcl => pcl.Category)
.WithMany(s => s.ProductsLinks)
.HasForeignKey(s => s.CategoryId);
}
Context
It's not required but most likely you'll need to save links directly to context, so let's define a DbSet for them.
public class MyContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category > Categories{ get; set; }
public DbSet<ProductCategoryLink> ProductCategoriesLinks { get; set; }
}
Two ways of implementation
Another reason why I used attributes to define relations is that it shows (both marked with [Key] attribute (also pay attention to [Column(Order=X)] attribute])) that two FKs in ProductCategoriesLink entity become a composite PK so you don't need to define another property like "ProductCategoryLinkId" and mark it as a special PK field.
You always could find desired linking entity all you need is just both PK's:
using(var context = new MyContext)
{
var link = context.ProductCategoriesLinks.FirstOrDefault(pcl => pcl.ProductId == 1
&& pcl.CategoryId == 2);
}
Also this approach restricts any chance to save several links with the same Product and Category as they are complex key. If you prefer the way when Id is separated from FK's you'll need to add UNIQUE constraint manually.
Whichever way you choose you'll reach your aim to manipulate the links as you need and add additional properties to them if you need.
Note 1
As we defined many-to-many links as separate entity Product and Category don't have direct relation to each other anymore. So you'll need to update your code:
Instead of adding Product directly to Category or Category directly to Product now you need to define a ProductCategoryLink entity and save it using one of three ways depending on your logic's context:
public void AddProductToCategory(Product product, Company company)
{
using (var context = new MyContext())
{
// create link
var link = new ProductCategoryLink{
ProductId = product.ProductId, // you can leave one link
Product = product, // from these two
CategoryId = category.CategoryId, // and the same here
Category = category
};
// save it
// 1) Add to table directly - most general way, because you could
// have only Ids of product and category, but not the instances
context.ProductCategoriesList.Add(link);
// 2) Add link to Product - you'll need a product instance
product.CategoriesLinks.Add(link);
// 3) Add link to Category - you'll need a category instance
category.ProductLinks.Add(link);
context.SaveChanges();
}
}
Note 2
Also remember as your properties now navigate to ProductCategoryLinks (not to Products for categories and not for Categories for products) if you need to query the second linked entity you need to .Include() it:
public IEnumerable<Product> GetCategoryProducts(long categoryId)
{
using (var context = new MyContext())
{
var products = context.Categories
.Include(c => c.ProductsCategoriesLinks.Select(pcl => pcl.Product))
.FirstOrDefault(c => c.CategoryId == categoryId);
return products;
}
}
UPD:
There is a same question with detailed answer on SO:
Create code first, many to many, with additional fields in association table
If you need a model like you posted (a "clean" model) you need to disable automatic migration and create the table by yourself. EF will not handle Id so it has to be autonumbering.
If you need to handle and see Id inside your app, your model is different and the Junction table must have a class in the model.
I have a table called Products which obviously contains products.
However, I need to create related products. So what I've done is create a junction table called product_related which has two PKs. ProductID from Products table and RelatedID also from Products table.
I already use EF and have set up everything on other tables. How should I add this properly in order to create a relationship with products as such:
product.Products.Add(product object here). Of course here product represent a product object that I've fetched from the db using db.Products.FirstOr....
How should I do this properly ? A many to many to the same table?
Thanks.
In order to create a many-to-many relationship with Database-First approach you need to setup a database schema that follows certain rules:
Create a Products table with a column ProductID as primary key
Create a ProductRelations table with a column ProductID and a column RelatedID and mark both columns as primary key (composite key)
Don't add any other column to the ProductRelations table. The two key columns must be the only columns in the table to let EF recognize this table as a link table for a many-to-many relationship
Create two foreign key relationships between the two tables:
The first relationship has the Products table as primary-key-table with the ProductID as primary key and the ProductRelations table as foreign-key-table with only the ProductID as foreign key
The second relationship also has the Products table as primary-key-table with the ProductID as primary key and the ProductRelations table as foreign-key-table with only the RelatedID as foreign key
Enable cascading delete for the first of the two relationships. (You can't do it for both. SQL Server won't allow this because it would result in multiple cascading delete paths.)
If you generate an entity data model from those two tables now you will get only one entity, namely a Product entity (or maybe Products if you disable singularization). The link table ProductRelations won't be exposed as an entity.
The Product entity will have two navigation properties:
public EntityCollection<Product> Products { get { ... } set { ... } }
public EntityCollection<Product> Products1 { get { ... } set { ... } }
These navigation collections are the two endpoints of the same many-to-many relationship. (If you had two different tables you wanted to link by a many-to-many relationship, say table A and B, one navigation collection (Bs) would be in entity A and the other (As) would be in entity B. But because your relationship is "self-referencing" both navigation properties are in entity Product.)
The meaning of the two properties are: Products are the products related to the given product, Products1 are the products that refer to the given product. For example: If the relationship means that a product needs other products as parts to be manufactured and you have the products "Notebook", "Processor", "Silicon chips" then the "Processor" is made of "Silicon chips" ("Silicon chips" is an element in the Products collection of the Processor product entity) and is used by a "Notebook" ("Notebook" is an element in the Products1 collection of the Processor product entity). Instead of Products and Products1 the names MadeOf and UsedBy would be more appropriate then.
You can safely delete one of the collections from the generated model if you are only interested in one side of the relationship. Just delete for example Products1 in the model designer surface. You can also rename the properties. The relationship will still be many-to-many.
Edit
As asked in a comment the model and mapping with a Code-First approach would be:
Model:
public class Product
{
public int ProductID { get; set; }
public ICollection<Product> RelatedProducts { get; set; }
}
Mapping:
public class MyContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasMany(p => RelatedProducts)
.WithMany()
.Map(m =>
{
m.MapLeftKey("ProductID");
m.MapRightKey("RelatedID");
m.ToTable("product_related");
});
}
}
Lets take your Example:
Related table
Related_id PK
Related_name
Date
Product Table
Product_id PK
Related_id FK
Product_Name
Date
How to Represent it in EF
Related Model Class named as RelatedModel
[Key]
public int Related_id { get; set; }
public string Related_name {get;set}
public Datetime Date{get;set;}
Product Model Class named as ProductModel
[Key]
public int Product_id { get; set; }
public string Product_name {get;set}
public string Related_id {get;set}
public Datetime Date{get;set;}
[ForeignKey("Related_id ")] //We can also specify here Foreign key
public virtual RelatedModel Related { get; set; }
In this way we can Create Relations between Two table
Now In Case of Many to Many Relation I would like to take another Example here
Suppose I have a Model Class Enrollment.cs
public class Enrollment
{
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public decimal? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
Here CourseID and StudentId are the two foreign Keys
Now I Have another Class Course.cs where we will create Many to Many Relation.
public class Course
{
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
Hope This will help!!!
I'm just a beginner in EF code first model. Given two POCO classes mapped to current legacy MS SQL database. They are associated with a composite foreign key setting up one to many relation. Since it's actually one-to-one relation I'd like to have corresponding navigation properties in my POCO objects and do mapping in fluent API. Here is my example:
public partial class Answer
{
//primary key
public int id { get; set; }
//foreign keys
public int question { get; set; }
public int assignedForm { get; set; }
//simple fields
public short state { get; set; }
public int author { get; set; }
//navigation property
public virtual AssignedQuestion AssignedQuestion { get; set; }
}
public partial class AssignedQuestion
{
// primary keys
public int id { get; set; }
public int assignedForm { get; set; }
//simple field
public string content { get; set; }
//navigation property
//public virtual ICollection<Answer> Answers { get; set; }
public virtual Answer Answer { get; set; }
}
If I wanted to do one-to-many relation I would simply uncomment "Answers" collection and have Fluent API mapping:
modelBuilder.Entity<AssignedQuestion>()
.HasKey(q => new { q.id, q.assignedForm });
modelBuilder.Entity<Answer>()
.HasRequired(a => a.AssignedQuestion)
.WithMany(aq=>aq.Answers)
.HasForeignKey(a => new { a.question,a.assignedForm});
My goal is to go with one-to-one relation and use "Answer" property in AssignedQuestion with such Fluent API as:
modelBuilder.Entity<AssignedQuestion>()
.HasKey(q => new { q.id, q.assignedForm });
modelBuilder.Entity<Answer>()
.HasRequired(a => a.AssignedQuestion)
.WithOptional(aq => aq.Answer);
//.HasForeignKey(a => new { a.question, a.assignedForm });
The problem is I can't specify exactly foreign key fields (as in previous example) and uncomment HasForeignKey call. In this case EF tries to join tables using conventional field names "AssignedQuestion_ID" and "AssignedQuestion_AssignedForm" instead of "question" and "assignedForm" in Answer table. Is there a walkaround in Fluent API other than changing field names?
It is not one-to-one relationship so your first mapping is correct. The reason why it is one-to-many is that EF understands one-to-one only when build on PKs on both sides. If AssignedQuestion has PK id and assignedForm your Answer will need to have FK and PK on its id and assignedForm otherwise EF doesn't see it as one-to-one relation. Even if you mark your question and assignedForm with unique constaint in database (to make it one-to-one in the database) EF will still not be able to handle it as one-to-one because it doesn't support unique constraints yet (except PK).