Understanding Foreignkey Attribute in Entity Framework Code First

Understanding ForeignKey attribute in entity framework code first

The required side of the 1..0 relationship MemberDataSet should not have a FK to DeferredData. Instead, DeferredData's PK should also be a FK to MemberDataSet (known as shared primary key)

public class MemberDataSet
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }

public virtual DeferredData DeferredData { get; set; }
}

public class DeferredData
{
// DeferredData.Id is both the PK and a FK to MemberDataSet
[Key]
[DatabaseGenerated( DatabaseGeneratedOption.None )]
[ForeignKey( "MemberDataSet" )]
public int Id { get; set; }

[Required]
public virtual MemberDataSet MemberDataSet { get; set; }
}

Fluent API:

modelBuilder.Entity<MemberDataSet>()
.HasOptional( mds => mds.DeferredData )
.WithRequired()
.WillCascadeOnDelete();

Entity Framework - Code First - Foreign Key Constraint

To add a foreign key just add this on the Product class add:

public int ProducerId { get; set; }

[ForeignKey("ProducerId")] //This attribute is optional bc EF should recognize Product obj specifi

public virtual Producer Producer { get; set; }

By adding public virtual Producer Producer EF Core should recognize the ProducerId property as a foreign key. virtual is used to enable Lazy Loading if you like.

The [ForeignKey()] is an optional attribute to explicitly point to the foreign and navigation keys. This post should further explain the optional use of [ForeignKey()].
How Should I Declare Foreign Key Relationships Using Code First Entity Framework (4.1) in MVC3?

To be clear, to simply add a foreign key, all that is required is adding this to class:

public int ProducerId { get; set; }
public virtual Producer Producer { get; set; }

How Should I Declare Foreign Key Relationships Using Code First Entity Framework (4.1) in MVC3?

If you have an Order class, adding a property that references another class in your model, for instance Customer should be enough to let EF know there's a relationship in there:

public class Order
{
public int ID { get; set; }

// Some other properties

// Foreign key to customer
public virtual Customer Customer { get; set; }
}

You can always set the FK relation explicitly:

public class Order
{
public int ID { get; set; }

// Some other properties

// Foreign key to customer
[ForeignKey("Customer")]
public string CustomerID { get; set; }
public virtual Customer Customer { get; set; }
}

The ForeignKeyAttribute constructor takes a string as a parameter: if you place it on a foreign key property it represents the name of the associated navigation property. If you place it on the navigation property it represents the name of the associated foreign key.

What this means is, if you where to place the ForeignKeyAttribute on the Customer property, the attribute would take CustomerID in the constructor:

public string CustomerID { get; set; }
[ForeignKey("CustomerID")]
public virtual Customer Customer { get; set; }

EDIT based on Latest Code
You get that error because of this line:

[ForeignKey("Parent")]
public Patient Patient { get; set; }

EF will look for a property called Parent to use it as the Foreign Key enforcer. You can do 2 things:

1) Remove the ForeignKeyAttribute and replace it with the RequiredAttribute to mark the relation as required:

[Required]
public virtual Patient Patient { get; set; }

Decorating a property with the RequiredAttribute also has a nice side effect: The relation in the database is created with ON DELETE CASCADE.

I would also recommend making the property virtual to enable Lazy Loading.

2) Create a property called Parent that will serve as a Foreign Key. In that case it probably makes more sense to call it for instance ParentID (you'll need to change the name in the ForeignKeyAttribute as well):

public int ParentID { get; set; }

In my experience in this case though it works better to have it the other way around:

[ForeignKey("Patient")]
public int ParentID { get; set; }

public virtual Patient Patient { get; set; }

Code First entity framework and foreign keys

First change your code to this

public class Movie
{
int ID{ get; set; }
string MovieName {get; set; }
List<Actor> Actors {get; set; }
}

public class Actor
{
int ID{get;set}
string ActorName{ get; set }
Movie Movie{ get; set; }
int MovieID{ get; set; }
}

By convention EF will know that MovieID is the foreign key to Movie

Then change Actor code to this:

public class Actor
{
int ID{get;set}
string ActorName{ get; set; }
Movie Movies{ get; set; }
}

Actors appear in many movies. Movies have many actors.... :-)

But going back to your one-to-many where an actor only appears in one movie - if you really want the foreign key to be Move_ID then add a data annotation:

[ForeignKey("Move_ID")]
Movie Movie{ get; set; }

Or configure it using FluentAPI

   modelBuilder.Entity<Actor>()
.HasRequired(c => c.Movie)
.WithMany(d => d.Actors)
.HasForeignKey(c => c.Move_ID);

ForeignKey attribute on Entity Framework

They already are FK in your Auction class. They will be mapped as FK. You might want to use lazy loading later on so:

public class Auction {
public int Id { get; set;}

public virtual User Seller {get; set;}
public virtual User Winner {get; set;}
}

Also you don't need the [Key] annotation above property called Id.

Update after question was edited:

You might need to enable migrations. Go to the Package Manager Console, if it is not open you can open it via menu View at the menu bar of the Visual Studio.

Then write in it enable-migrations enter, then set AutomaticMigrations in the generated class to true, then again in Package Manager console write update-database, run your application.

Foot notes:

You didn't state what kind of app your are creating but usually keeping user password is a bad idea. You usually suppose to keep hashed version of it.

EF6 Code first model ForeignKey

A quick guide through ForeignKey property.

When used on a key property (such as int RemoteBenchmarkId), its name should point to the navigation property (e.g. Benchmark RemoteBenchmark).
When used on a navigation property (this time Benchmark RemoteBenchmark) its name should point to the key property (such as int RemoteBenchmarkId).

The following code fragments are equivalent:

public class Context {
//...other properties

[ForeignKey("RemoteBenchmark")]
public int RemoteBenchmarkId { get; set; }
public Benchmark RemoteBenchmark { get; set; }
}
public class Context {
//...other properties

public int RemoteBenchmarkId { get; set; }

[ForeignKey("RemoteBenchmarkId")]
public Benchmark RemoteBenchmark { get; set; }
}

With that in mind, what you probably want is 4 benchmarks, each having their own foreign key column (two benchmark properties using same key would point to the same instance, which is probably not what you want), like here:

public class Context {
//...other properties

[ForeignKey("RemoteBenchmark")]
public int RemoteBenchmarkId { get; set; }
public Benchmark RemoteBenchmark { get; set; }

[ForeignKey("DataCenterBenchmark")]
public int DataCenterBenchmarkId { get; set; }
public Benchmark DataCenterBenchmark { get; set; }

[ForeignKey("IISBenchmark")]
public int IISBenchmarkId { get; set; }
public Benchmark IISBenchmark { get; set; }

[ForeignKey("LocalBenchmark")]
public int LocalBenchmarkId { get; set; }
public Benchmark LocalBenchmark { get; set; }
}

Don't forget to use [Required] annotation if context requires specific benchmarks!

Also, you might skip the [ForeignKey] annotations entirely allowing EF to infer columns itself (named <navigation property name>_Id by default, such as RemoteBenchmark_Id), but then you can't retrieve ids themselves without retrieving entire benchmark. Guess it all depends on specific cases; personally, I don't mind cluttering model with foreign key properties, since sometimes the keys themselves are enough.

(at least [ForeignKey] annotations shouldn't be necessary; if their lack causes errors, it might be another problem entirely...?)

Cheers~!

Entity Framework Code First Foreign Key issue

It is possible set by yourself the Id of BaseCard, but first you have to use Fluent Api to specify this and the one-to-many relationship. Also, at this way, you don't have to specify attributes in your model classes. Your model classes would be like this:

public class BaseCard
{
public int Id {get ; set; }

public virtual ICollection<Skill> Skills { get; set; }
}

public class Skill
{
public int Id { get; set; }

public int BaseCardId { get; set; }
public virtual BaseCard BaseCard { get; set; }
}

As you can see, I change the navigation properties as virtual.If you define your navigation property as virtual EF will at runtime create a new class (dynamic proxy) derived from your BaseCard class and use it instead (the same happens with Skill). This new dynamically created class contains logic to load navigation property when accessed for the first time. This feature is called lazy loading.It enables Entity Framework to avoid loading an entire tree of dependent objects which are not needed from the database. You can find more info about this subject in these posts:Why Navigation Properties are virtual by default in EF and Entity Framework 4.1 Virtual Properties.

The other change that I proporse in your model is use ICollection<> type instead List<> in the Skills property. As you can see in this post, an Interface is good practice in this case. It lets you later specify the implementation that you want (could be a List<>).

Now, back to your problem,in your Context class you need to override the OnModelCreating method to specify the relationship and the no autogenerate column for Id in the BaseCards table.

public class YourContext : DbContext
{
public DbSet<BaseCard> BaseCards { get; set; }

public DbSet<Skill> Skill { get; set; }

//...

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure the primary key for BaseCard
modelBuilder.Entity<BaseCard>().HasKey(t => t.Id);
//specify no autogenerate the Id Column
modelBuilder.Entity<BaseCard>().Property(b => b.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

//one-to-many relationship
modelBuilder.Entity<Skill>().HasRequired(c => c.BaseCard)
.WithMany(s => s.Skills)
.HasForeignKey(c => c.BaseCardId);
}
}

With this configuration, you have to set always the Id of BaseCard objects with a different value.

If you prefer use data annotations it is possible specify the same at this way:

public class BaseCard
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public virtual ICollection<Skill> Skills { get; set; }
}

public class Skill
{
[Key]
public int Id { get; set; }

public int BaseCardId { get; set; }

[ForeignKey("BaseCardId")]
public virtual BaseCard BaseCard { get; set; }
}

My recomendation is use Fluent API, it's more flexible and you don't have to touch your model classes. You can see some useful cosiderations in this post



Related Topics



Leave a reply



Submit