Entity Framework 6: Relationship without using Primary Key - entity-framework

Let's say I have a data model that looks like so:
dbo.Application
{
int Id { get; set; }
int ClientAlternateId { get; set; }
...
public virtual Client Client { get; set; }
}
dbo.Client
{
int Id { get; set; }
int AlternateId { get; set; }
string Name { get; set; }
...
}
Where the primary key on both tables is the Id column. the Application type is associated to the Client table via its AlternateId column (which is not a key). The data in this column is always unique.
Is there a way to get entity framework to map this? I don't believe I'll be able to use:
HasRequired(t => t.Client).WithMany().HasForeignKey(c => c.ClientAlternateId);
since that field is not the primary key.

When configuring the relationship in your AppDbContext you need to add .HasPrincipalKey()
, this article might help
https://gavilan.blog/2019/04/14/entity-framework-core-foreign-key-linked-with-a-non-primary-key/

Related

EF Core 2 duplicate column created with foreign key relationship

I'm trying add migration using EF core 2 code first method. The issue is that, the entities with foreign key relationship are created with a foreign key id suffixed with '1' at the end and a redundant column with the same name but without the 1 at the end which is not a foreign key.
Examples are my 2 classes, Store and StoreVisit as shown below:
Store
[Table("Store")]
public class Store
{
public Store()
{
StoreVisits = new HashSet<StoreVisit>();
}
[Key]
public int StoreId { get; set; }
[StringLength(30)]
public string ShopName { get; set; }
[StringLength(50)]
public string ShopKeeper { get; set; }
public string ContactNo { get; set; }
[StringLength(70)]
public string Address { get; set; }
[StringLength(20)]
public string Street { get; set; }
[StringLength(50)]
public string City { get; set; }
public IEnumerable<StoreVisit> StoreVisits { get; set; }
}
Store Visit
[Table("StoreVisit")]
public class StoreVisit
{
[Key]
public int StoreVisitId { get; set; }
[StringLength(50)]
public string Location { get; set; }
[StringLength(50)]
public string Notes { get; set; }
[DataType(DataType.Time)]
public DateTime StartTime { get; set; }
[DataType(DataType.Time)]
public DateTime EndTime { get; set; }
public Store Store { get; set; }
}
The Visit class is created in the database with the column shown in the image below:
As you can see, the StoreVisit table has columns "StoreId1" which is the actual foreign key and "StoreId" which is not a foreign key.
I have even configured the relationship with Fluent API as below:
modelBuilder.Entity<Store>()
.HasMany(c => c.StoreVisits)
.WithOne(e => e.Store)
.IsRequired();
Can someone help.
Note that Entity Framework Core is smart enough to detect relationships among your classes which will be turned into database tables with relationships if you use its conventions. So this is redundant to use annotations like [Key] above StoreId property.
Second thing, As an advice, try to use simple and clean names for classes or properties as they can be potentially similar to those automatically created by EF. For example, in your case I prefer to avoid using store inside StoreVisit class name again (e.g in case of many to many relationship, derived table is named StoreVisit like one that you employed just without 's', Although your case is one to many),
And Final tip is the reason for appearing redundant StoreId column. Actually, In your case, this is not necessary to use Fluent API as EF can detect the relationship. In addition, you've written wrong configuration for modelBuilder. So remove it and let EF to generate it (unless you plan to have fully defined relationship to consume its advantages in your code).
The StoreId is one that you told EF to generate it (as required)
in modelBuilder.
The StoreId1 is EF Auto generated column (Foreign Key) based on one
to many relationship. '1' is appended in order to avoid column name duplication.
A foreign key needs to be defined on the class.
[Table("StoreVisit")]
public class StoreVisit
{
[Key]
public int StoreVisitId { get; set; }
public int StoreId { get; set; }
[StringLength(50)]
public string Location { get; set; }
[StringLength(50)]
public string Notes { get; set; }
[DataType(DataType.Time)]
public DateTime StartTime { get; set; }
[DataType(DataType.Time)]
public DateTime EndTime { get; set; }
public Store Store { get; set; }
}
It also would hurt to add the foreign key reference to the Fluent API.
modelBuilder.Entity<Store>()
.HasMany(c => c.StoreVisits)
.WithOne(e => e.Store)
.HasForeignKey(e => e.StoreId)
.IsRequired();

How can I update a Code First application to accommodate manual schema changes?

I have an app that was created using EF. The problem is that I noticed some extraneous foreign keys columns created in one of the tables. Dropping these columns causes an [SqlException (0x80131904): Invalid column name 'Material_Id' error.
Here is a simplified version of the class structure...
public class Hazard
{
public int Id { get; set; }
public string Name { get; set; }
}
public abstract class HazardAnalysis
{
public int Id { get; set; }
public int HazardId { get; set; }
public virtual Hazard Hazard { get; set; }
}
public class ProductHazard : HazardAnalysis
{
public int ProductId { get; set; }
public virtual Product Product { get; set; }
}
The table that was generated looked like this...
dbo.Hazards
Id int
Name string
Product_Id int
Since the relationship between ProductHazards and Hazards is 1:many, the Product_Id field should not be there. Dropping this column generates the Invalid column name 'Product_Id' error.
I've scoured the model for hours and can't find any valid reason for this column to exist.
Is there any way to update the model after manually dropping a column? I obviously don't want to drop and recreate the database.
I've also noticed that the productId of the current product is inserted in the dbo.Hazards Product_Id table whenever a new ProductHazard is created. Since there is a many-to-one relationship between ProductHazards and Hazards, when a new ProductHazard is created, the Product_Id field is updated with the ProductId of the new ProductHazard, which seems bizarre.
Any advice would be greatly appreciated.
Here is the DbSet code:
public DbSet<Hazard> Hazards { get; set; }
public DbSet<HazardAnalysis> HazardAnalyses { get; set; }
and also...
modelBuilder.Entity<HazardAnalysis>()
.HasRequired(e => e.Hazard)
.WithMany()
.HasForeignKey(e => e.HazardId)
.WillCascadeOnDelete(false);
You need to define the many part of the relationship. In this case, you need to add a collection property to your Hazard object, like below:
public class Hazard
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<HazardAnalysis> HazardAnalyses { get; set; }
}

Entity Framework Code First Not Pulling Navigation Property

I have a problem with a navigation property not being loaded. I have this same setup with all my other entities, but this is using a property that isnt a natural FK (Number) and wont cascade, that will be handled by a trigger.
Expression<Func<DivisionBracketGameParticipant, object>>[] includes2 = {
q => q.DivisionWinnerBracketGame,
q => q.DivisionLoserBracketGame
};
var test = _divisionBracketGameParticipantsRepository.GetMany(includes2,
q =>
q.DivisionBracketGame.DivisionBracket.Division.
EventId == eventId);
Database Schema
DivisionBracketGame
Id
Number
DivisionBracketGameParticipant
Id
DivisionBracketGameId -> Id
DivisionBracketGameWinnerNumber -> Number
DivisionBracketGameLoserNumber -> Number
Entities
[Table("DivisionBracketGame", Schema = "GrassrootsHoops")]
public class DivisionBracketGame : BaseEntity
{
public int Id{ get; set; }
public int Number { get; set; }
[InverseProperty("DivisionBracketGame")]
public virtual ICollection<DivisionBracketGameParticipant> DivisionBracketGameParticipants { get; set; }
[InverseProperty("DivisionWinnerBracketGame")]
public virtual ICollection<DivisionBracketGameParticipant> DivisionWinnerBracketGameParticipants { get; set; }
[InverseProperty("DivisionLoserBracketGame")]
public virtual ICollection<DivisionBracketGameParticipant> DivisionLoserBracketGameParticipants { get; set; }
}
[Table("DivisionBracketGameParticipant", Schema = "GrassrootsHoops")]
public class DivisionBracketGameParticipant : BaseEntity
{
public int Id{ get; set; }
public virtual int DivisionBracketGameId { get; set; }
public virtual int? DivisionWinnerBracketGameNumber { get; set; }
public virtual int? DivisionLoserBracketGameNumber { get; set; }
[ForeignKey("DivisionBracketGameId")]
public virtual DivisionBracketGame DivisionBracketGame { get; set; }
[ForeignKey("DivisionWinnerBracketGameNumber")]
public virtual DivisionBracketGame DivisionWinnerBracketGame { get; set; }
[ForeignKey("DivisionLoserBracketGameNumber")]
public virtual DivisionBracketGame DivisionLoserBracketGame { get; set; }
}
EF will not create relation to Number because it is not a primary key. Primary key is of your DivisionBracketGame is Id so both DivisionWinnerBracketGame and DivisionLoserBracketGame are targeting Id (not Number).
One-to-many relation demands that column in principal table is unique - in your case the column should be a Number. This is possible in database by either using primary key from principal table or by using unique index on that column. EF doesn't support unique indexes / candidate keys so the only way to build one-to-many relation in EF is through primary key of principal table.
The FK value is used to get related value so at the moment it probably looks for records with wrong value because it uses a wrong column.

Self referencing / parent-child relationship in Entity Framework

I read quite a number of posts of programmers that run into the Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values -exception when using a self-referencing relationship in Entity Framework.
I am trying to get a parent-child relationship to work:
public class Category {
public int CategoryId { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public Category Parent { get; set; }
public List<Category> Children { get; set; }
}
This is the configuration I use (Fluent API):
Property(c => c.ParentId).IsOptional();
HasMany(c => c.Children).WithOptional(c => c.Parent).HasForeignKey(c => c.ParentId);
//HasOptional(c => c.Parent).WithMany(c => c.Children).HasForeignKey(c => c.ParentId);
Both the HasMany() and HasOptional() configurations result in a "Unable to determine a valid ordering for dependent operations..." exception when I try to save a new category like this:
context.Categories.Add(new Category { Name = "test" });
I don't understand why EF doesn't insert the Category with a null parentId. The database allows the ParentId foreign key to be null.
Would you be able to tell me how to do this?
You must define the ParentId in the category class as nullable to use it as the foreign key property for an optional relationship:
public int? ParentId { get; set; }
An int property cannot take the value null and therefore cannot represent a NULL as value in a database column.
Since someone asked in a comment about doing this with attributes. You can also utilize data annotations to set this up. Using the same example as above:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Category {
// You can also add [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
// as an attribute, if this field is to be generated by the database
[Key] // Define this as the primary key for the table
public int CategoryId { get; set; }
public string Name { get; set; }
[ForeignKey(nameof(Parent))] // Link the Parent object to the ParentId Foreign Key
public int? ParentId { get; set; }
public Category Parent { get; set; }
public List<Category> Children { get; set; }
}
This is tested and works in EF 6.

Using two keys in Entity Framework 4, One Identity and one Foreign?

Is it possible to map an Entity with one identity index that auto increments and a foreign key linking it to another table?
public class Item
{
public int ItemID { get; set; }
[StringLength(20)]
public string Barcode { get; set; }
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
public string Description { get; set; }
public decimal Price { get; set; }
[ForeignKey("ItemCategory")]
public string CatID { get; set; }
public virtual ItemCategory ItemCategory { get; set; }
}
public class ItemCategory
{
// This should be the identity index
public int ItemCategoryID { get; set; }
// This should be the foreign key
public string CatID { get; set; }
public string Name { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
I saw this answer - should I configure my tables with modelbuilder?
Foreign key in Item must point to primary key in ItemCategory. FKs in EF behave in exactly same way as in databases. It means that FK must point to property with unique values in the principal entity. The problem is that EF doesn't support unique index / constraint so the only way to achieve uniqueness is primary key.
Because of that you cannot point your FK to CatID unless it is part of primary key but in such case you will have composite key containing both ItemCategoryID and CatID and your Item class will have to contain both of them to form correct FK.