Navigation Property other than primary key in self referencing table - entity-framework

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

Related

EF 0..1 to 0..1 relationship without shared primary key

I have two entities which I would like to configure an optional 1-1 relationship (i.e. 0..1 to 0..1). I would like to do this using a key only on one entity, while having navigation properties in both directions.
Consider the following simplified example to illustrate:
public class Person
{
public int PersonId { get; set; }
public int? TicketId { get; set; }
public virtual Ticket Ticket { get; set; }
}
public class Ticket
{
public int TicketId { get; set; }
public virtual Person Person { get; set; }
}
There are a number of People, and a number of Tickets. A person can possess at most one ticket. There are people with no ticket, and unclaimed tickets.
I thought the following might work:
modelBuilder.Entity<Person>()
.HasOptional(p => p.Ticket)
.WithOptionalPrincipal(t => t.Person);
But this creates an additional ID on the Ticket table.
I know this is possible using two optional relationships, but this is not an ideal solution as it requires two calls to SaveChanges, and does not guarantee referential integrity (e.g. Person1 could own Ticket1, but Ticket1 could point to Person2).
Similar questions have usually focussed on a 1-0..1 relationship where the principal entity's primary key can be used on the dependent - this is not suitable either.
I am using EF6 Code-First.

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

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

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.