One to one optional relationship using Entity Framework Fluent API
EF Code First supports 1:1
and 1:0..1
relationships. The latter is what you are looking for ("one to zero-or-one").
Your attempts at fluent are saying required on both ends in one case and optional on both ends in the other.
What you need is optional on one end and required on the other.
Here's an example from the Programming E.F. Code First book
modelBuilder.Entity<PersonPhoto>()
.HasRequired(p => p.PhotoOf)
.WithOptional(p => p.Photo);
The PersonPhoto
entity has a navigation property called PhotoOf
that points to a Person
type. The Person
type has a navigation property called Photo
that points to the PersonPhoto
type.
In the two related classes, you use each type's primary key, not foreign keys. i.e., you won't use the LoyaltyUserDetailId
or PIIUserId
properties. Instead, the relationship depends on the Id
fields of both types.
If you are using the fluent API as above, you do not need to specify LoyaltyUser.Id
as a foreign key, EF will figure it out.
So without having your code to test myself (I hate doing this from my head)... I would translate this into your code as
public class PIIUser
{
public int Id { get; set; }
public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}
public class LoyaltyUserDetail
{
public int Id { get; set; }
public double? AvailablePoints { get; set; }
public PIIUser PIIUser { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<LoyaltyUserDetail>()
.HasRequired(lu => lu.PIIUser )
.WithOptional(pi => pi.LoyaltyUserDetail );
}
That's saying LoyaltyUserDetails PIIUser
property is required and PIIUser's LoyaltyUserDetail
property is optional.
You could start from the other end:
modelBuilder.Entity<PIIUser>()
.HasOptional(pi => pi.LoyaltyUserDetail)
.WithRequired(lu => lu.PIIUser);
which now says PIIUser's LoyaltyUserDetail
property is optional and LoyaltyUser's PIIUser
property is required.
You always have to use the pattern HAS/WITH.
HTH and FWIW, one to one (or one to zero/one) relationships are one of the most confusing relationships to configure in code first so you are not alone! :)
Optional One to many Relationship using entity framework (fluent Api)
The problem is that your model and configuration does not match. In the fluent API you're configuring the foreign key of the dependent to be optional but in your model the foreign key is required:
In your Person
class change:
public int DepartmentId
to
public int? DepartmentId
This way you ensure that the foreign key can actually have the value 'NULL' in the database.
EF Core: Optional one-to-one foreign key relation from content entity
set optional FK in model builder
[Table("shops")]
public class Shop
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("shop_name")]
public string ShopName{ get; set; }
public virual ICollection<Transaction> Transactions { get; set;}
}
modelBuilder.Entity<Shop>()
.HasMany(c => c.Transactions)
.WithOptional(c => c.Shop)
.HasForeignKey(c => c.ShopId)
.WillCascadeOnDelete(false);
if you are looking only for EF core then you can refer this link :
WithOptional with Entity Framework Core
One-to-One optional relationship with both ends optional and both FKs
In any one-to-one association, EF uses only one foreign key. When the association is required, the foreign key will also be the primary key of the dependent entity, as explained here.
When the association is optional, both entities should be able to exist independent of one another. So their primary keys can't be foreign keys, because PKs can't be optional. Here an additional nullable FK field is required to establish the optional association.
In your case, technically it doesn't really matter which entity has the FK field (logically, it may). I've used this model:
public class Review
{
[Key]
public int ReviewId { get; set; }
public virtual Payment Payment { get; set; }
}
public class Payment
{
[Key]
public int PaymentId { get; set; }
public Review Review { get; set; }
}
With this mapping:
public class ReviewConfiguration : EntityTypeConfiguration<Review>
{
public ReviewConfiguration()
{
// One-to-One Optional
HasOptional(s => s.Payment)
.WithOptionalDependent(s => s.Review)
.Map(s => s.MapKey("PaymentId"));
}
}
(So, apart from Payment.ReviewId
, this is identical to the model + mapping in your question).
Now I can do things like ...
db.Set<Review>().Add(new Review { Payment = new Payment() });
db.Set<Payment>().Add(new Payment { Review = new Review() });
db.SaveChanges();
... where db
of course is a context. The content of both tables now is:
PaymentId
-----------
1
2
ReviewId PaymentId
----------- -----------
1 1
2 2
And I can query the data bidirectionally like so:
var data = db.Set<Review>().Include(r => r.Payment).ToList();
or
var data = db.Set<Payment>().Include(r => r.Review).ToList();
But instead of ReviewConfiguration
, I can also use...
public class PaymentConfiguration : EntityTypeConfiguration<Payment>
{
public PaymentConfiguration()
{
// One-to-One Optional
HasOptional(s => s.Review)
.WithOptionalDependent(s => s.Payment)
.Map(s => s.MapKey("ReviewId"));
}
}
Now there will be an FK field ReviewId
in table Payment
, and the rest of the code works without changes.
EF Code First - 1-to-1 Optional Relationship
One solution would be;
public class User
{
[Key]
public string Username { get; set; }
public virtual Contact Contact { get; set; }
}
public class Contact
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public virtual User User { get; set; }
}
modelBuilder.Entity<User>()
.HasOptional<Contact>(u => u.Contact)
.WithOptionalDependent(c => c.User).Map(p => p.MapKey("ContactID"));
You set only your navigational objects in your POCOs and instead you use fluent API to map your key to the correct column.
EF Core 2.0.0 One to One-or-Zero with Fluent Api
You could just specify int? as EmployeeId property type.
BTW, no need to make navigation properties virtual.
Related Topics
Compare Version Numbers Without Using Split Function
"The Given Path's Format Is Not Supported."
Send HTML Email via C# with Smtpclient
Using Static Variables Instead of Application State in ASP.NET
Internet Explorer Protective Mode Setting and Zoom Levels
What .Net Collection Provides the Fastest Search
Linq Select Objects in List Where Exists in (A,B,C)
Ef 4.1 - Code First - JSON Circular Reference Serialization Error
How Is Gethashcode() of C# String Implemented
Populate Data Table from Data Reader
Automapper Convert from Multiple Sources
Using Itextsharp to Extract and Update Links in an Existing PDF
Is There an Alternative to Bastard Injection? (Aka Poor Man's Injection via Default Constructor)
How to "Multiply" a String (In C#)
Use Xml Includes or Config References in App.Config to Include Other Config Files' Settings