Why is Code First Entity Framework generating a foreign key? - mapping

So I've got...
public class User
{
public int ManagerId { get; set; }
public Manager Manager { get; set; }
}
public class Manager
{
public User User { get; set; }
}
modelBuilder.Entity<User>()
.HasOptional(x => x.Manager)
.WithOptionalDependent(x => x.User);
Thus a user has an optional Manager and a Manager may or may not have a User. This works in that Manager doesn't have a foreign key to a User but a User has a nullable foreign key to a Manager. But its generating the foreign key and treating ManagerId as a regular property. How do I fix this?
Cheers, Ian.

It is one-to-one relation. It works only if the foreign key is built on top of primary key. You need something like this:
public class User
{
[Key, ForeingKey("Manager")]
public int Id { get; set; }
public Manager Manager { get; set; }
}
public class Manager
{
public int Id { get; set; }
public User User { get; set; }
}
If manager has a user, user must have the same PK value as manager. You will not be able to define such relation optional on both sides because it would violate FK. In fluent mapping you should do something like:
modelBuilder.Entity<Manager>()
.HasOptional(m => m.User)
.WithRequired(u => u.Manager);

Related

EDMX/ EF Remove Existing primary key column and add new column with primary key

I have folowwing scenario in ASP.net MVC - code first
[Table("api")]
public class Api
{
[Column("Id")]
public int Id { get; set; }
[Column("api_key")]
public string ApiKey { get; set; }
public virtual BookingPluginConfig BookingPluginConfig { get; set; }
}
public class BookingPluginConfig
{
[Key,ForeignKey("Api")]
public int ApiId { get; set; }
public virtual Api Api { get; set; }
}
Currently "Api" table to "BookingPluginConfig" have one to one relationship - I want to change it to one to many
'BookingPluginConfig' table has
[Key,ForeignKey("Api")]
public int ApiId { get; set; }
I want to remove this column which is the primary key, and I want to add new column as the primary key (auto increment)
Currently this 'ApiId ' is primary key as well foreign key. I want to remain ''ApiId '' is foreign key but not as primary key
I have already many data in existing table
How can I do this?
Your modified BookingPluginConfig class:
public class BookingPluginConfig
{
[Key(), Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[ForeignKey("Api")]
public int ApiId { get; set; }
public virtual Api Api { get; set; }
}
Navigation property, which is the only change, in the API class:
//one to many relation to BookingPluginConfig
public virtual ICollection<BookingPluginConfig> BookingPluginConfigs { get; set; }
That's all you need to add a new primary key and define relation. Take back up of database if you want, add migration and update database.

How to create composite primary key on multiple accessor properties in Entity Framework 6

I'm trying to create a composite key based on three navigation properties in Entity Framework 6 : ManufacturingBundle_Id, Part_Id and Process_Id
Here is my PartProcess class I use at the moment with Id being the Primary key:
public class PartProcess
{
public int Id { get; set; }
public virtual ManufacturingBundle ManufacturingBundle { get; set; }
public virtual Part Part { get; set; }
public virtual Process Process { get; set; }
}
At the moment I get the automatically generated database table that has the following Columns:
Id | ManufacturingBundle_Id | Part_Id | Process_Id
where Id is the Primary key. I would like to get rid of the Id Column and make a composite Primary key based on ManufacturingBundle_Id, Part_Id and Process_Id
So I tried overloading the OnModelCreating method but this doesn't seem to work on typed objects, the debuggers says the properties need to be ints.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// create a composite primary key for PartProcess https://www.learnentityframeworkcore.com/configuration/fluent-api/haskey-method
modelBuilder.Entity<PartProcess>()
.HasKey(o => new { o.ManufacturingBundle, o.Part, o.Process });
base.OnModelCreating(modelBuilder);
}
How must I declare this composite primary key because I use navigation properties and the ManufacturingBundle_Id, Part_Id and Process_Id properties are autogenerated by Entity Framework?
Thanks for your help,
Ephie
Assuming ManufacturingBundle has a ManufacturingBundleId field for instance, you'd need to configure your model as follows:
public class PartProcess
{
public int ManufacturingBundleId { get; set; }
public virtual ManufacturingBundle ManufacturingBundle { get; set; }
public int PartId { get; set; }
public virtual Part Part { get; set; }
public int ProcessId { get; set; }
public virtual Process Process { get; set; }
}
Then it should let you create the composite key on the model creation, as you outlined above.

Are foreign key nullable by default in ASP.Net MVC 5 application

I am in a learning phase. And I want to know are foreign keys created by ASP.NET MVC-5 framework in Code First convention using entity framework nullable by default? I tried to create foreign key relationship and the foreign key column turns out to be nullable. I had a notion that if I mark a column as foreign key it should be marked as NOT NULLABLE by entity framework.
Below is the example:
One to Many: One "Standard" can have many "Children".
public class Children
{
public int Id { get; set; }
public string Name { get; set; }
public int StandardId { get; set; }
[ForeignKey("StandardId")]
public virtual Standard Standard { get; set; }
}
public class Standard
{
public Standard()
{
Children = new List<Children>();
}
public int Id { get; set; }
public string StandardName { get; set; }
public virtual ICollection<Children> Children { get; set; }
}
With just above configuration, the Foreign Key "StandardId" is coming out to be Nullable in database. I just want to know is this expected behaviour? Are foreign keys are suppose to be NULLABLE by DEFAULT or I have not wired up foreign key property properly?
You must tell EF explicitly, that you want this field to be not nullable:
public class YourContext : DbContext
{
public DbSet<Children> Childrens { get; set; }
public DbSet<Standard> Standards { get; set; }
protected override void OnModelCreating(DbModelBuilder dBModelBuilder)
{
modelBuilder.Entity<Children>().HasRequired(x => x.Standard);
}
}

Fluent API mapping other side if a 1-1 relationship

I have a relationship set up between 2 tables using code first and Fluent API. This works and the schema is generated with the correct fields and key assignments. However, my problem is I need to be able to say SupplyPoint.SupplyPointPricing in my resultant Model. What I have below only gives me the other way around.
I figure there must be a way to keep the structure I have but just MAP SupplyPoint.
public partial class SupplyPoint
{
[Key]
public int SupplyPointId { get; set; }
public string SupplyPointName { get; set; }
}
public class SupplyPointPricing
{
public int SupplyPointPricingId { get; set; }
public int? SupplyPointId { get; set; }
[ForeignKey("SupplyPointId")]
public virtual SupplyPoint SupplyPoint { get; set; }
}
Then I use Fluent API and this gives me the 1-1 between the tables and the Schema I expect
modelBuilder.Entity<SupplyPointPricing>()
.HasOptional(a => a.SupplyPoint)
.WithMany()
.HasForeignKey(u => u.SupplyPointId);
Last time I had this problem I had to change the design around and have a foreign key in the SupplyPoint table. On that previous occasion that was OK since it was a 1-1 required where there are always a matching record. This time around I need to keep this structure since there is 1-0 between SupplyPoint and SupplyPointPricing.
This is how I have always done 1-to-1 relationships with my models, without using Fluent mapping:
public partial class SupplyPoint
{
[Key]
public int SupplyPointId { get; set; }
public virtual SupplyPointPricing SupplyPointPricing { get; set; }
}
public class SupplyPointPricing
{
[Key, ForeignKey("SupplyPoint")]
public int SupplyPointId { get; set; }
public virtual SupplyPoint SupplyPoint { get; set; }
}
As you can see, the SupplyPointPricing does not have an Id of its own, but only the Id of the SupplyPoint, which acts as a key in the 1-to-1 relatioship.
The only thing I'm not sure of is if the SupplyPointId can be a nullable int.
This will not create a foreign key on the SupplyPoint, so if you don't have a Pricing, the SupplyPoint.SupplyPointPricing property will be null.

"principal end of an association" - EF

Unable to determine the principal end of an association between the
types 'XYZ.Models.Attachment' and 'XYZ.Models.Accounts.User'. The
principal end of this association must be explicitly configured using
either the relationship fluent API or data annotations.
Exception has been thrown by the target of an invocation.
That error I get, when I try to update-database with my EF Models.
Part of User.cs:
[Table("Users")]
public class User
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public int MainPhotoId { get; set; }
[ForeignKey("MainPhotoId")]
public virtual Attachment Photo { get; set; }
}
Attachment.cs
[Table("Attachments")]
public class Attachment
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int AttachmentId { get; set; }
public string name { get; set; }
public int UserId { get; set; }
public DateTime AddDate { get; set; }
public bool del { get; set; }
[ForeignKey("UserId")]
public virtual User Author { get; set; }
}
Why I get this error? And how to resolve it?
Regards
Mapping conventions detect a one-to-one relationship between User.Photo and Attachment.Author and cannot infer what the principal and what the dependent end is. Hence the exception.
Actually, according to your comments, you want two relationships and not a single one-to-one relationship. You can achieve that only by overriding the convention with Fluent API and you probably need to make one of the relationships optional because otherwise you have a circular mutual dependency between User and Attachment. You can, for example, make the User.Photo property optional by choosing a nullable foreign key:
public int? MainPhotoId { get; set; }
Then the mapping would look like this:
modelBuilder.Entity<User>()
.HasOptional(u => u.Photo)
.WithMany()
.HasForeignKey(u => u.MainPhotoId);
modelBuilder.Entity<Attachment>()
.HasRequired(a => a.Author)
.WithMany()
.HasForeignKey(a => a.UserId);
With this mapping you can remove the [ForeignKey] attributes because the definition of the FK properties is part of the Fluent API mapping (HasForeignKey).

Resources