One sided one-to-one relationship in Entity Framework - c#

I have two model classes (Tickets and Activities), where Activities is more like a look-up table, and is not suppose to hold any navigational properties or FK's of other entities.
A record in Tickets is supposed to have a single Activity, but in the whole table of Tickets, there will be many of the same Activities. Activities needs to be a table, and not (for example) an enum, because of the possibility of future updates and amendments.
Although this seems trivial enough, I keep encountering errors like Identity is Set to off.
My models:
public class Tickets
{
public int ID {get; set;}
// fk
public int ActivityID {get; set;
// nav property
public Activity Activity {get; set;}
// other properties.
}
public class Activity
{
public int ID {get; set;}
public int RankOrder {get; set;}
//other properties
}
I have specified a domainmapping for the Tickets model:
builder.HasOne(t => t.Activity)
.WithMany()
.HasForeignKey(t => t.ActivityID);
based on this SO-post and blogpost: here and here but I don't get it to work, my most recent error message is:
SqlException: Cannot insert explicit value for identity column in table 'Activity' when IDENTITY_INSERT is set to OFF.
Also, with this mapping it seems that EF created a Ticket column in the Activity table, something that I don't want.

Try this
builder.Entity<Ticket>()
.HasOne(t => t.Activity)
.WithMany(a => a.Ticket)
.HasForeignKey(t => t.ActivityID);

Related

Entity Framework One-To-Many with only one navigation property: WithRequiredDependant?

Using the newest Entity Framework I have a class with a one-to-many wit only one navigation property on the many side.
As stated in MSDN: Entity Framework Fluent API - Relationships:
A one-directional (also called unidirectional) relationship is when a
navigation property is defined on only one of the relationship ends
and not on both.
Simplified: a School has many Students; there is a one-to-many relation between School and Student, but the School doesn't have a property containing the collection of Students
class Student
{
public int Id {get; set;}
// a Student attends one School; foreign key SchoolId
public int SchoolId {get; set;}
public School School {get; set;}
}
class School
{
public int Id {get; set;}
// missing: public virtual ICollection<Studen> Students {get; set;}
}
In a two-directional relationship, you could write the following fluent API in OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.HasRequired(student => student.School)
.WithMany(school => school.Students)
.HasForeignKey(student => student.SchoolId);
}
Because of the lack of School.Students, I need to do something extra. According to the link at the beginning it seems that I'd have to do something with WithRequiredDependant.
// Summary:
// Configures the relationship to be required without a navigation property
// on the other side of the relationship. The entity type being configured will
// be the dependent and contain a foreign key to the principal. The entity type
// that the relationship targets will be the principal in the relationship.
//
public ForeignKeyNavigationPropertyConfiguration WithRequiredDependent();
modelBuilder.Entity<Student>()
.HasRequired(student => student.School)
.WithRequiredDependent();
Alas, this doesn't work. SchoolId is not modeled as the foreign key.
What fluent API do I need?
I hope I have the right version/edition in mind:
modelBuilder.Entity<Student>()
.HasRequired(student => student.School)
//.WithMany(school => school.Students)
.WithMany()
.HasForeignKey(student => student.SchoolId);

Entity Framework, Create 0-1 relation with existed entity

I have an existing entity User. Now I am trying to create a new entity Contact with 0-1 relation with User.
class Contact
{
public int Id {get; set;}
public string Name {get; set;}
public int? UserId {get; set;}
public virtual User TheUser{get; set;}
}
All suggestion involve about something like this:
modelBuilder.Entity<User>()
.HasOptional(t => t.TheUser)
.WithOptionalDependent(u => u.TheConatct);
But this means we have to add TheConatct property to the existed User entity. Actually I do not want to make any modification to the existed entity. All what I need to define a foreign key form Contact to User entity and can access the User entity from Contact via TheUser property.
Update:
If I use ForeignKey attributes to annotate the property:
class Contact
{
public int Id {get; set;}
public string Name {get; set;}
public int? UserId {get; set;}
[ForeignKey("UserId")]
public virtual User TheUser{get; set;}
}
Then, the result of ObjectContext.CreateDatabase() will also include create statements for already existed tables (depending on the entities that have relations with User).
Of course we are talking about "Entity Framework 6 Code First", Also, I have the same problem with 1-1 relation.
The idea, I cannot alter the existing entity User to add additional property for the new entity Contact
I wonder if there is a way to overcome this issue
Just use another overload:
modelBuilder.Entity<User>()
.HasOptional(t => t.TheUser)
.WithOptionalDependent();
I don't know which version of Entity Framework you are using and I assume you are using Code First, but you may have to consider using a one to many relationship instead of a 0-1.
I don't believe there is support for 0-1 in the way you want it, but you can simulate by having a one to many (even though your "many" will only ever by 1)

Use association properties with Entity Framework

I am just to set up a model in which you have news articles and topics they belong to. This is a simple association but now it get's a bit "extended". One of those topic association can be marked as the "mainTopic".
I've set up 3 tables:
avsn_content, containing the newsArticles identified by id
avsn_content_topics, containing the assoc, having assocId, id, topicId and a column indicating the mainTopic
avsn_topics, containing the topic, identified by topicId
Furthermore, I have models for these three tables. My association model is designed as follows:
[Table("avsn_content_topcis")]
public class TopicNewsModel
{
[Key]
[Column("assocId")]
public int Id { get; set; }
public NewsArticleModel NewsArticle { get; set; }
public TopicModel Topic { get; set; }
[Column("mainTopic")]
public bool IsMainTopic { get; set; }
}
My relationship setup looks like this:
modelBuilder.Entity<NewsArticleModel>()
.HasMany(x => x.Topics)
.WithMany()
.Map(m => m.MapLeftKey("id")
.MapRightKey("topicId")
.ToTable("avsn_content_topics"));
I am getting this error:
One or more validation errors were detected during model generation:
NewsArticleModelTopicNewsModel: Name: The EntitySet
'NewsArticleModelTopicNewsModel' with schema 'dbo' and table
'avsn_content_topics' was already defined. Each EntitySet must refer
to a unique schema and table.
Removing the ToTable option does not help it, so what am I doing wrong here?
Well, found the answer right after posting this. Trying to pick the problem from the other end of the rope showed that I had to start off from the TopicNewsModel instead from the NewsModel.
modelBuilder.Entity<TopicNewsModel>()
.HasRequired(topicNews => topicNews.NewsArticle)
.WithMany(news => news.Topics)
.Map(m => m.MapKey("id"));
modelBuilder.Entity<TopicNewsModel>()
.HasRequired(topicNews => topicNews.Topic)
.WithMany()
.Map(m => m.MapKey("topicId"));

One-to-one relationship in Entity Framework states that Multiplicity is not valid

In our MVC4 application we have a WeekDay Model:
public class WeekDay
{
[Key]
public int WeekDayId { get; set; }
[Required]
[Display(Name = "Dag")]
public string Day { get; set; }
[ForeignKey("Shop")]
public int ShopId { get; set; }
public virtual Shop Shop { get; set; }
}
And Shop model:
public class Shop
{
public int ShopId { get; set; }
[Display(Name = "Winkel")]
public string Name { get; set; }
public int WeekDayId { get; set; }
public virtual WeekDay WeekDay { get; set; }
public virtual ICollection<Category> Categories { get; set; }
}
We need a one-to-one relationship from WeekDay to Shop and the other way around (so that every shop has a weekday and vice versa). Unfortunately the code above gives the following error:
Multiplicity is not valid in Role 'Shop_WeekDay_Target' in relationship 'Shop_WeekDay'. Because
the Dependent Role properties are not the key properties, the upper bound of the multiplicity of
the Dependent Role must be '*'.
We've tried various things found on the internet to solve this issue but none seem to work (it did build when we added two primary keys, but then it fails while running the seed method and we get this error: The index 'IX_ShopId' is dependent on column 'ShopId'.
ALTER TABLE ALTER COLUMN ShopId failed because one or more objects access this column.).
Does anyone know how a one-to-one relationship can be made in this case?
/Edit Adding:
modelBuilder.Entity<WeekDay>()
.HasRequired(a => a.Shop)
.WithMany()
.HasForeignKey(u => u.ShopId);
modelBuilder.Entity<Shop>()
.HasRequired(a => a.WeekDay)
.WithMany()
.HasForeignKey(u => u.WeekDayId);
To the DbContext makes a succesful migration, but on update-database gives the error:
Introducing FOREIGN KEY constraint 'FK_dbo.WeekDays_dbo.Shops_ShopId'
on table 'WeekDays' 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.
And setting WillCascadeOnDelete to false gives the error:
The index 'IX_ShopId' is dependent on column 'ShopId'. ALTER TABLE
ALTER COLUMN ShopId failed because one or more objects access this
column.
/Edit 3
My database structure looks as follows:
Now I "solved" the issue by not making the one-to-one relationship only one way, so that to match the Shop with the WeekDay I need to query the WeekDay table first and then see which shop matches. Then I can use the ShopId in further queries to only select the Categories from the current shop. It would have been cleaner if you could go from Shop to WeekDay so that I only need to query once.
I do not care if it is one to many if it is hard to make (I will only use one from the many), but it should be the other way around (from shop to weekday instead of weekday to shop). The one to many is the wrong way around as can be seen in the upper right.
The first issue I notice is here:
modelBuilder.Entity<WeekDay>()
.HasRequired(a => a.Shop)
.WithMany()
.HasForeignKey(u => u.ShopId);
modelBuilder.Entity<Shop>()
.HasRequired(a => a.WeekDay)
.WithMany()
.HasForeignKey(u => u.WeekDayId);
Each of the configurations above defines a one-to-many relationship. If you want a one-to-one relationship it should look something like this (check my syntax as I am not at my dev workstation to verify):
modelBuilder.Entity<WeekDay>()
.HasRequired(a => a.Shop)
.WithRequiredDependent();
Or, optionally, you can do this as well:
modelBuilder.Entity<WeekDay>()
.HasRequired(a => a.Shop);
modelBuilder.Entity<Shop>()
.HasRequired(a => a.WeekDay);

Entity Framework Parent Child - Child refers to parent more than once

I have a situation with EF5 and a complex object. The basics is that I have a parent to child complex object, but the child refers back to the parent, more than once. I have tried various options but am not finding a solution that answers the question. The closest I have got is this answer (option 2c)
My model looks like below:
public class StaffMember
{
public virtual Guid StafId { get; set; }
// other props
// List of leave apps (Approved/Cancelled etc)
public virtual ICollection<StaffLeaveApp> LeaveApps { get; set; }
}
//Staff Leave Application
public class StaffLeaveApp
{
public virtual Guid LeaveId { get; set; }
public virtual Guid StaffId { get; set; }
// other props...
// Leave approved by? (2 approvals required)
public virtual StaffMember ApprovedBy1 { get; set; }
public virtual StaffMember ApprovedBy2 { get; set; }
}
my mappings look like this
public class StaffMap : EntityTypeConfiguration<StaffMember>
{
public StaffMap()
{
ToTable("tblStaffMembers");
HasKey(x => x.StaffId);
// other mappings...
HasMany(x => x.LeaveApps);
}
}
public class StaffLeaveAppMap: EntityTypeConfiguration<StaffLeaveApp>
{
public StaffLeaveAppMap()
{
ToTable("tblStaffMembersLeaveApps");
HasKey(x => x.LeaveId);
Property(x => x.StaffId).HasColumnName("StaffID");
//Child Relationships
HasOptional(x => x.ApprovedBy1).WithMany().Map(m => m.MapKey("LeaveApprovedBy1"));
HasOptional(x => x.ApprovedBy2).WithMany().Map(m => m.MapKey("LeaveApprovedBy2"));
}
}
Table (sorry, no images)
StaffID uniqueidentifier (FK - tblStaffMembers)
LeaveID uniqueidentifier (PK)
LeaveApprovedBy1 uniqueidentifier (FK - tblStaffMembers)
LeaveApprovedBy2 uniqueidentifier (FK - tblStaffMembers)
The business rule says: a staff member has "many" leave applications and a leave application belongs to a single staff member. Each application requires the approval of 2 staff members (managers) before it is "approved".
How would I map the above using EF so that a single staff member has a "many" leave applications (working already) and a leave application is mapped back to a staff member whom approved it for the first approval and then again for the seond approval. If I use the one mapping for "ApprovedBy1" only then EF is happy and all works as expected. The moment I add the second approval mapping EF struggles with the SQL queries it generates.
I am not sure how to tell EF to map back to the StaffMembers table to specify whom approved the application at level 1 and whom approved it at level 2. It almost ends up being a many to many relationship.
Any ideas?
You are looking for the inverse property, which is the property at the other end of an association. In EF, there are two way to mark a property as inverse.
Data annotations: InversePropertyAttribute.
Fluent mapping
As you already have fluent mapping I'll show you how you'd do it there:
HasOptional(x => x.ApprovedBy1).WithMany(x => x.LeaveApps)
.HasForeignKey(s => s.StaffId);
HasOptional(x => x.ApprovedBy2).WithMany()
.Map(m => m.MapKey("LeaveApprovedBy2"));
The HasOptional(...).WithMany(...) pair is a way to map inverse properties. Coming from the other side you can use e.g. HasMany(....).WithOptional(...).

Categories