Entity Framework 1 to 1 relationship using code first. how? - entity-framework

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; }

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.

Navigation Property other than primary key in self referencing table

I have a table named Customer and it has two properties ReferrerCode and OwnReferrerCode. When a customer registers, he/she can put a referrer code of another customer and the system will assign a unique OwnReferrerCode. Multiple customers can use a specific customer's refer code.
public class Customer
{
[PrimaryKey]
public long CustomerId {get;set;}
public string ReferrerCode {get;set;}
public string OwnReferrerCode {get;set;}
public Customer ReferrerCustomer { get; set; }
public ICollection<Customer> ReferredCustomers { get; set; }
}
And in config file:
this.HasOptional<Customer>(s => s.ReferrerCustomer).WithMany(g => g.ReferredCustomers)
.HasForeignKey(s => s.ReferrerRewardCode);
It obviously returns this error
The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role.
Is there any way to do that kind of relation in EF6
As you explained, the customer entity may have one referrer customer, so the relation is like a child-parent relation. child-parent optional relationship entity-framework

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; }

One to one OPTIONAL relationship

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.

One-to–Zero-or-One relationship, with self

I have the following entity:
public class Category
{
public int ID { get; set; }
public int? ParentID { get; set; }
public string Name{ get; set; }
public virtual Category Parent { get; set; }
}
to which I'm trying to define a relationship: a Category can optionally have a parent category.
I've already defined the primary key:
HasKey(m => m.ID);
I've read this example, which includes a One-to–Zero-or-One relationship, but I can't grasp exactly how HasRequired implies an entity is optional in a relationship.
I think a side problem is also that you cannot reference the exact same class to itself as a parent in EF, what you can use is Projection in order to have different attributes for the same type.
HasOptional in the child reference has the same effect as saying I may have a parent or not
In the example you quote a child has a ParentId which is both a primary key and a foreign key. That is OK when parent and child are different entities (and different database tables), but not when they are self referencing. Category would have to have an ID that's both primary and foreign. But a primary key should be unique, so there's literally no room for a 1:1 child that should share the same key.
What can you do? I think the only option is to map the association as 1:n and enforce a business rule that n can't be greater than 1. Note that this is not an EF restriction. There's just no conceivable relational database model to constrain a self referencing association to 1:1.