Entity Framework 4.1 Inverseproperty Attribute and Foreignkey

Entity Framework 4.1 InverseProperty Attribute and ForeignKey

It is theoretically correct but SQL server (not Entity framework) doesn't like it because your model allows single employee to be a member of both First and Second team. If the Team is deleted this will cause multiple delete paths to the same Employee entity.

This cannot be used together with cascade deletes which are used by default in EF code first if you define foreign key as mandatory (not nullable).

If you want to avoid the exception you must use fluent mapping:

public Context : DbContext
{
public DbSet<Employee> Employees { get; set; }
public DbSet<Team> Teams { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

modelBuilder.Entity<Employee>()
.HasRequired(e => e.SecondTeam)
.WithMany(t => t.SecondEmployees)
.HasForeignKey(e => e.FirstTeamId)
.WillCascadeOnDelete(false);

...
}
}

This will result in scenario where you must delete members of SecondTeam manually before you delete the team.

Entity Framework 4.1 InverseProperty Attribute

I add an example for the InversePropertyAttribute. It cannot only be used for relationships in self referencing entities (as in the example linked in Ladislav's answer) but also in the "normal" case of relationships between different entities:

public class Book
{
public int ID {get; set;}
public string Title {get; set;}

[InverseProperty("Books")]
public Author Author {get; set;}
}

public class Author
{
public int ID {get; set;}
public string Name {get; set;}

[InverseProperty("Author")]
public virtual ICollection<Book> Books {get; set;}
}

This would describe the same relationship as this Fluent Code:

modelBuilder.Entity<Book>()
.HasOptional(b => b.Author)
.WithMany(a => a.Books);

... or ...

modelBuilder.Entity<Author>()
.HasMany(a => a.Books)
.WithOptional(b => b.Author);

Now, adding the InverseProperty attribute in the example above is redundant: The mapping conventions would create the same single relationship anyway.

But consider this example (of a book library which only contains books written together by two authors):

public class Book
{
public int ID {get; set;}
public string Title {get; set;}

public Author FirstAuthor {get; set;}
public Author SecondAuthor {get; set;}
}

public class Author
{
public int ID {get; set;}
public string Name {get; set;}

public virtual ICollection<Book> BooksAsFirstAuthor {get; set;}
public virtual ICollection<Book> BooksAsSecondAuthor {get; set;}
}

The mapping conventions would not detect which ends of these relationships belong together and actually create four relationships (with four foreign keys in the Books table). In this situation using the InverseProperty would help to define the correct relationships we want in our model:

public class Book
{
public int ID {get; set;}
public string Title {get; set;}

[InverseProperty("BooksAsFirstAuthor")]
public Author FirstAuthor {get; set;}
[InverseProperty("BooksAsSecondAuthor")]
public Author SecondAuthor {get; set;}
}

public class Author
{
public int ID {get; set;}
public string Name {get; set;}

[InverseProperty("FirstAuthor")]
public virtual ICollection<Book> BooksAsFirstAuthor {get; set;}
[InverseProperty("SecondAuthor")]
public virtual ICollection<Book> BooksAsSecondAuthor {get; set;}
}

Here we would only get two relationships. (Note: The InverseProperty attribute is only necessary on one end of the relationship, we can omit the attribute on the other end.)

Why does EF Code First [InverseProperty] attribute fail to work when used with [ForeignKey] attribute?

Same behaviour in EF 4.1.

You didn't mention the option to move the InverseProperty attribute to the other side of the relationship:

[Table("Matches")]
public class Match
{
[Key]
public long Id { get; set; }

[ForeignKey("Player1Home")]
public long? HPlayer1Id { get; set; }

[InverseProperty("MatchesAsHome1")]
public virtual Player Player1Home { get; set; }
}

[Table("Players")]
public class Player
{
[Key]
public long Id { get; set; }

public virtual ICollection<Match> MatchesAsHome1 { get; set; }
}

This worked for me and didn't create the extra column.

The behaviour of your option 2 looks like a code-first bug to me.

Edit

Confirming that changing the version from EF 4.1 to EF 4.3.1 causes a NullReferenceException with the model above. The database doesn't get created.

EF 4.1 code first with one-to-many relationship creates duplicate foreign keys

Because there are two navigation properties User and Users in Profile that refer to the User entity EF cannot decide by a convention which of the two belongs to the inverse property Profile in entity User. You must EF give a hint using the [InverseProperty] attribute:

[InverseProperty("Users")]
public virtual Profile Profile { get; set; }

Now, it defines that User.Profile is the inverse navigation property of Profile.Users and that both are ends of the same relationship. Without the attribute EF assumes that the two navigation properties are ends of two different relationships and one of them is responsible for the additional foreign key Profile_Id.

Here is a bit more background.

MVC modelbuilding: multiple foreign keys in table, code first EF

After some more research I found it's simply not possible to have multiple lists in one object refer to a single key in the objectype that fills the list. The way to handle this issue is to use the DataAnnotation 'InverseProperty' like shown here: https://stackoverflow.com/a/25366822/3191144

This means that it is required to have one reference-object for each list you want to keep. For my case I had to do the following:

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

[InverseProperty("Game")]
List<Action> ActiveActionList {get;set;}
[InverseProperty("PassiveGame")]
List<Action> PassiveActionList {get;set;}
... (several other variables)
}

public class Action
{
public int Id {get;set;}
Game Game {get;set;}
Game PassiveGame {get;set;}
...(several other variables)
}

Unfortunately this also means I'll have one column that is almost always null (PassiveActions are rarer than ActiveActions) but I guess that's the way it works. For more than two lists I suppose it's better to change the architecture or something and use subclasses to avoid getting a load of columns to simply keep track of which list the item is in.

Should someone find a way to have 1 column in the Action table as a link to the game and another way to keep track of the two lists, please do reply :)

ASP.NET MVC are two foreign fields in dependent class of One to Many relationship legal

If your link entity is going to have 2 foreign keys pointing back to the same parent, you will need 2 navigational properties as well and then use the InverseProperty attribute to tell EF which belongs to which. https://msdn.microsoft.com/en-us/data/jj591583.aspx#Relationships

// dependent class
public class Link {
//Other fields here...

public string StartingLocation { get; set;}
public string EndingLocation { get; set;}

[InverseProperty("StartingLocation")]
public Location StartLoc { get; set;}

[InverseProperty("EndingLocation")]
public Location EndLoc { get; set;}

}

This assumes StartingLocation and EndingLocation are foreign keys and you have used the fluent API to configure them as such since you are not following the "Id" convention.

Multiple foreign keys pointing to same table in Entity Framework 4.1 code first

EF is not able to determine by convention which navigation properties on your 2 classes belong together and creates 4 relationships (without an end on the other side) instead of 2 (with ends on both sides). This problem occurs always when you have more than one navigation property of the same type (Company in your case) in the same class. You could try to fix this the following way:

public class SellerDebtor
{
public int SellerDebtorId { get; set; }
[ForeignKey("DebtorCompany")]
public int DebtorCompanyId { get; set; }
[ForeignKey("SellerCompany")]
public int SellerCompanyId { get; set; }

[InverseProperty("SellerDebtorDebtorCompanies")]
public Company DebtorCompany { get; set; }
[InverseProperty("SellerDebtorSellerCompanies")]
public Company SellerCompany { get; set; }

public ICollection<SellerDebtorInfo> SellerDebtorInfos { get; set; }
public ICollection<SellerDebtorFile> SellerDebtorFiles { get; set; }
}

[InverseProperty(...)] defines the navigation property on the other end of the relationship and it tells EF explicitely which pairs of navigation properties belong together in a relationship.

EF5 InverseProperty Issue

When you use [InverseProperty] at both ends of a 1:1 association it is not clear who the principal should be. The principle is the entity the other end (the dependent) refers to by a foreign key. Even though you tell EF that EditoredBy and CurrentlyWorkingBookId both are part of one association it still would be possible to have a foreign key field for EditoredBy in Book (that wouldn't show in the class model).

Admittedly, one could contend that you've told EF enough to create the database model properly. EF could have logic that says: if I've been told about one foreign key in a 1:1 association, then I know who the principle should be. However, unfortunately it doesn't.

So I would use the fluent API to model this:

public class Author
{
public int AuthorId { get; set; }
public ICollection<Book> Books { get; set; }
public Book CurrentlyWorkingBook { get; set; }
}

public class Book
{
public int BookId { get; set; }
public int AuthorId { get; set; }
public Author Author { get; set; }
public Author EditoredBy { get; set; }
}

In OnModelCreating:

modelBuilder.Entity<Author>()
.HasMany(a => a.Books)
.WithRequired(b => b.Author)
.HasForeignKey(b => b.AuthorId);
modelBuilder.Entity<Author>()
.HasOptional(a => a.CurrentlyWorkingBook)
.WithOptionalDependent(b => b.EditoredBy)
.Map(m => m.MapKey("CurrentlyWorkingBookId"));

Personally, I like the fluent API because the lambda expressions allow compile-time checks and it is much more conspicuous which ends comprise one association.

As you see, CurrentlyWorkingBookId can not be part of the class model in this scenario. That is because an OptionalNavigationPropertyConfiguration (the return type of WithOptionalDependent) doesn't have HasForeignKey method. I'm not sure why not. I think it should be possible to set a primitive FK value (CurrentlyWorkingBookId) as well as a reference property (CurrentlyWorkingBook).



Related Topics



Leave a reply



Submit