One to one OPTIONAL relationship - entity-framework

Traditional EF questions starts with: My models are
public class Ingredient
{
public int IngredientID { get; set; }
public virtual RequestedIngredient RequestedIngredient { get; set; }
// other stuff
}
public class RequestedIngredient
{
[Key]
string BlahBlahBlah { get; set; }
public int? IngredientID { get; set; }
public virtual Ingredient Ingredient { get; set; }
}
Somewhere in dbContext...
modelBuilder.Entity<Ingredient>()
.HasOptional<RequestedIngredient>(e => e.RequestedIngredient)
.WithOptionalPrincipal(e => e.Ingredient)
.Map(e => e.MapKey("IngredientID"))
.WillCascadeOnDelete(false);
But I get Schema specified is not valid. Errors:
(195,6) : error 0019: Each property name in a type must be unique. Property name 'IngredientID' was already defined.
If I remove IngredientID from RequestedIngredient, the db will be created just as I want to. But I have no access to IngredientID. How can I set this up to have access to foreign key?

This is not one-to-one relationship. In one-to-one relationship the foreign key must be a primary key. Which is not the case in this example. This is one-to-many, but I assumed that my app will take care of making sure there's only one association.
EF can deal with that using Independent Association. It will create foreign key, hidden from your POCO class. One can specify the name of the column using MapKey as I did. However, because I also created a property called IngredientID, just as the column used with MapKey, the EF has a problem as two properties are mapped to the same column.
So things like that are possible in EF, but you can't use foreign key anymore.

Related

How to change foreign key suffix in Entity Framework Core?

In EF Core with a code-first approach, by default column referencing another entity has an Id suffix - for example PersonId.
Is it possible - and if so, how? - to change it to _id, so to person_id?
Create the foreign key explicitly under the name you want - in your case Parent_Id. Keep a navigation property and foreign key property.
public int Parent_ID { get; set; }
public virtual Parent Parent { get; set; }
Map the foreign key relations using .HasForeignKey(). Something similar as below
builder.HasOne(d => d.Prop)
.WithMany(p => p.NavigationProp)
.HasForeignKey(d => d.ForeignKeyProp)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_ConstraintName");
If you prefer data annotation, you could also use
[Column("Parent_ID")]
public int ParentID { get; set; }
To add to WisdomSeeker's answer, you can use a [ForeignKey] annotation to point at a shadow property for the FK.
Given a class like a Course with a Person reference for a Teacher:
public class Course
{
[Key]
public int Id {get; set;}
// other fields.
[ForeignKey("person_id")]
public virtual Person Teacher { get; set; }
}
Alternatives as above would be:
[ForeignKey("Teacher")]
public int person_id { get; set; } // Not recommended naming convention in code.
public virtual Person Teacher { get; set; }
or
[Column("person_id"), ForeignKey("Teacher")]
public int TeacherId { get; set; }
public virtual Person Teacher { get; set; }
I generally avoid adding FK fields into classes as this leads to two sources of truth for what Teacher is assigned to a course. You have course.TeacherId and course.Teacher.Id, which could differ on update prior and after a SaveChanges. Shadow properties help avoid confusion and keep data updates consistent.
Using [Column] is common in Db-First implementations where you want to use a C# naming convention for properties to use in-code, but abide by existing/desired DB naming conventions in the database. I don't generally recommend using DB naming conventions in C# classes.

EF: Unable to determine the principal end of an association between the types

Unable to determine the principal end of an association between the types. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
Models:
`
[Table("Employees")]
public class Employee : Entity
{
public string Name { get; set; }
public int? AbsenceId { get; set; }
[ForeignKey("AbsenceId")]
public virtual Absence Absence { get; set; }
}
[Table("Absences")]
public class Absence : Entity
{
public DateTime From { get; set; }
public DateTime To { get; set; }
public string Reason { get; set; }
public int? SubstituteId { get; set; }
[ForeignKey("SubstituteId")]
public virtual Employee Substitute { get; set; }
}
`
The Employee have a Absence that can have a Employee that is not same Employee that have a Absence mentioned.
Any solution for this case?
Well, first of all.. You do not need to specify ForeignKey when you are following the Entity Framework conventions. By convention, EF will reocognize the fact that your Navigation property is called Foo and your ForeignKey will be called FooId.
However, the real problem is that you are attempting to create a 1:1 association between two entities and EF does not support associations like this.
EF only supports 1:1 associations with shared primary keys, that is where both tables have the same primary key and one table's PK is a FK to the other table's PK.
If you think about this, it makes sense. There is no native 1:1 relationship in SQL that does not have a shared primary key. If you add a FK in one table to the other, it creates a 1:Many. You can simulate a 1:1 by creating a unique constraint on the FK but EF does not support constraints.
Looking at your model. Do you really want a 1:1 anyways? Can an employee really only have a single absence? Ever? Probably not. You probably want Absence to be a 1:Many. So remove AbsenceId and change Absence to:
public virtual List<Absence> Absences { get; set; }

Fluent mapping for EF when foreign key not suffixed with ID

How to implement fluent mapping for the below scenario, I tried but it ends in vain.
I have two table Product and State, Product have column name State which hold StateCode like "WA", "NJ" etc which of string type. So i need to populate the State column into StateCode and the related State object into State property of the product entity.
Below is the classes i am using. I don't want to change the columns of table
public class Product
{
public int ID { get; set; }
public State State { get; set; }
public string StateCode { get; set; }
public string Description { get; set; }
}
public class State
{
public int Id { get; set; }
public string Code{get;set;}
public string Description{get;set;}
}
I tried the below mapping for Product
this.Property(t => t.StateCode).HasColumnName("State");
HasRequired(t => t.State).WithMany().HasForeignKey(t => t.StateCode);
No, currently it's not possible to have a Foreign Key column that refers to non PK in entity framework. Check this feature suggestion.
If you really want to have that feature, you need to have custom Seed that execute.
alter table Products add constraint FK_Products_States foreign key(State) references States(Code)
But you will not be able to populate State object. Putting public State State { get; set; } property will automatically create a Foreign Key column State_ID that refers to States::ID.
Otherwise you need to change the StateCode to be StateId (integer) that refers to State::Id.
The type of ForeignKey and PrimaryKey of referenced table must be the same. So you need to set State class Id property type to string. In EF you can only use foreig keys pointing to primary keys.

Entity Framework 1 to 1 relationship using code first. how?

I have two classes. How can I turn these two classes into a one to one relationship using the entity framework code first method?
public class Region
{
public int RegionId { get; set; }
public string Name { get; set; }
public virtual Factory _factory { get; set; }
}
public class Factory
{
public int FactoryId { get; set; }
public string Name { get; set; }
public virtual Region _region { get; set; }
}
When I try this, I get this error:
Multiplicity is not valid in Role 'Region_Factory_Source' in relationship 'Region_Factory'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
This occurs in CodeFirst because of the virtual keyword. In effect, you are creating a relationship where creating one item requires the creation of the other. however, the virtual keyword allows lazy instantiation, which means that creating an object of one type doesn't automatically create the other type, allowing the Id on the foreign item to be null. This implies a 0..1 relationship, but since each side is virtual, what you get is a 0..0 which isn't allowed.
There are 2 methods which you can use to remedy the situation.
remove the virtual option from either one side or both sides of the navigation properties, allowing for a 0..1 or a 1..1 map.
explicitly add a property for the Foreign key from the other entity on each object. i.e. on class Region add a property for FactoryId and on Factory add a property for RegionId
There are other ways to help Entity Framework determine which object is the Dependent Object, i.e. using Entity Framework Fluent api.
from MSDN
Configuring a Relationship Where Both Ends Are Required (One-to-One)
In most cases the Entity Framework can infer which type is the dependent and which is the principal in a relationship. However, when both ends of the relationship are required or both sides are optional the Entity Framework cannot identify the dependent and principal. When both ends of the relationship are required, use WithRequiredPrincipal or WithRequiredDependent after the HasRequired method. When both ends of the relationship are optional, use WithOptionalPrincipal or WithOptionalDependent after the HasOptional method.
the following code would create a Principal Factory with a Dependent Region
// Configure the primary key for the Region
modelBuilder.Entity<Region>()
.HasKey(t => t.RegionId);
modelBuilder.Entity<Factory>()
.HasRequired(t => t.Region)
.WithRequiredPrincipal(t => t.Factory);
EF6, add attributes:
[Key]
public int RegionId { get; set; }
[Key, ForeignKey("Region")]
public int FactoryId { get; set; }

EF Code First: Primary Key same as Foreign Key

I have two classes
public class Product
{
public Guid Id { get; set; }
public string ProductDetails { get; set; }
}
public class SpecialProductDetails
{
public Guid Product_Id { get; set; } // PK and FK to Product class
public string SpecialName { get; set; }
public string SpecialDescription { get; set; }
public virtual Product Product { get; set; }
}
SpecialProductDetails is mapped 1-1 with Product class and is optional. It shares the same PrimaryKey and ForeignKey.
In Fluent API i am mapping this relationship like this (inside SpecialProductDetails)
public SpecialProductDetails()
{
HasKey(p => p.Product_Id);
HasRequired(p => p.Product).WithMany().HasForeignKey(p => p.Product_Id).WillCascadeDelete(true);
}
This gives me this error when trying to generate the Database
\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'SpecialProductDetails_Product_Source' in relationship 'SpecialProductDetails_Product_Source'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.
How can i have a column set as PK and FK on EF Code First?
I'm quite sure you have already solved that, but I hit the same problem and the solution I found was:
public SpecialProductDetails()
{
HasKey(p => p.Product_Id);
HasRequired(p => p.Product).WithOptional();
}
"it worth noting that when we are mapping a one-to-one association with fluent API, we don't need to specify the foreign key as we would do when mapping a one-to-many association with HasForeignKey method. Since EF only supports one-to-one associations on primary keys, it will automatically create the relationship in the database on the primary keys."
after http://weblogs.asp.net/manavi/associations-in-ef-4-1-code-first-part-3-shared-primary-key-associations