Composite PK without key property - entity-framework

I using manual mapping entity in my Code First on EF5 project and would like to use FKs as composite PK. I have only navigation properties in mapping class (not FK) as mentioned below:
class MyMapping
{
public virtual Mapped1 {get;set;}
public virtual Mapped2 {get;set;}
}
I do not want to add fields like 'int Mapped1FK'/'int Mapped2FK', but I cannot find how to specify composite key in this case.
I assume that it should be something like:
modelBuilder.Entity<MyMapping>()
.HasKey(k => k.Mapped1)
.HasKey(k => k.Mapped2);
or
modelBuilder.Entity<MyMapping>()
.HasKey(k => { k.Mapped1, k.Mapped2} );
but I do not know what exactly right.

It's not possible to use navigation properties as primary key properties (no matter if composite or not). Key properties must have a primitive type - like int or string or Guid, etc.

As Slauma described it is impossible to do what I want without introducing primitive FK properties.
So I decided to work with my mapping entities as with ordinary POCO - inherits base class with
public int Id {get;set;}
declaration and use it as PK.
Also, in other sources, was recommended following, due architecture senses: when you converting simple mapping (2 FKs) to complex mapping (2FKs + custom field(s)) it becomes an ordinary entity as any other in project and should has the same constraints and structure.

Related

How can I configure a one to one relationship to have the foreign key also be a primary key?

I am trying to model a relationship like this:
public class MyContainer {
public int Id {get;set;}
}
public class MyCompontentOne
{
public MyContainer MyContainer {get;set;}
public string Prop1{get;set;}
}
I'd like to configure it to get a table like this:
MyContainerId (FK & PK) | Prop1 |... other props
I've tried a lot of things using the Fluent API but I always get some errors no matter what I do. This is the latest I've tried: (adding a shadow property and make it the foreign key)
mb.Entity<MyCompontentOne>().Property<int>("MyContainerId").IsRequired();
mb.Entity<MyCompontentOne>().Property(o => o.Prop1).IsRequired();
mb.Entity<MyCompontentOne>()
.HasOne(o => o.MyContainer)
.WithOne();
mb.Entity<MyCompontentOne>().HasKey("MyContainerId");
As mentioned in my answer to the suggested duplicate question EF Core One to One or Zero Relationship, shared PK association (dependent entity with PK being also a FK) is the default EF Core mapping of one to one or zero required relationship.
What is specific in your question though (and prevents applying directly the answer to the related post) is the lack of explicit property in the dependent entity to be mapped as PK/FK. So what you are asking is possible, but requires dealing with shadow properties.
The following is the minimal fluent configuration which will configure one to one or zero relationship between MyContainer (principal) and MyCompontentOne (dependent) with (1) navigation property MyContainer in MyCompontentOne, (2) no navigation property in MyContainer, and (3) required shadow FK property (and column) MyContainerId in MyCompontentOne. Then (4) will map the shadow property as a PK:
modelBuilder.Entity<MyCompontentOne>()
.HasOne(e => e.MyContainer) // (1)
.WithOne() // (2)
.HasForeignKey<MyCompontentOne>("MyContainerId") // (3)
.IsRequired();
modelBuilder.Entity<MyCompontentOne>()
.HasKey("MyContainerId"); // (4)

Exchanged Foreign Key on Entity Framework Code First From data base

I'm making a Windows Service using Code First From Database, but my code is throwing the following exception. Where can I change Foreign Key configuration of this class, because it looks like that the columns are cross-referenced, the column usu_grpcom must refer codagp and usu_codemp must refer codemp.
e013agp_usu_titefol_Source_e013agp_usu_titefol_Target: : The types of
all properties in the Dependent Role of a referential constraint must
be the same as the corresponding property types in the Principal
Role. The type of property 'usu_grpcom' on entity 'usu_titefol' does
not match the type of property 'codemp' on entity 'e013agp' in the
referential constraint 'e013agp_usu_titefol'.
e013agp_usu_titefol_Source_e013agp_usu_titefol_Target: : The types of
all properties in the Dependent Role of a referential constraint must
be the same as the corresponding property types in the Principal
Role. The type of property 'usu_codemp' on entity 'usu_titefol' does
not match the type of property 'codagp' on entity 'e013agp' in the
referential constraint 'e013agp_usu_titefol'.
Better you should share the classes implementation for better understanding. I'm providing you code according to my understanding. You can use the similar code to solve your problem.
public class usu_titefol
{
public e013agp e013agp { get; set; }
[ForeignKey("codemp")]
[Required]
public int usu_grpcom { get; set; }
}

EntityType 'x' has no key defined, Reuse DB First in Code First

I have a class named 'Authority' in a library that created by Database First method
As we know Database First generate all the classes automatically also Primary Key defined for each class,
I also created 'User' class has a property of Authority class, in another library I have 'PacsUser' class derived from 'User' I am using code first approach to develop 'PacsUser'
when I want PacsUser to return a specific user it gives me "EntityType 'Authority' has no key defined"
I have to define key for Authority class in OnModelCreating of PacsUserDBContext like:
modelBuilder.Entity<Authority>().HasKey(e => e.AID);
why DbModelBuilder in PacsUserDBContext recognize Authority's primary key automatically? or at least by
modelBuilder.Entity<Authority>().ToTable("Authority");
all things work properly (just for example).
They both(Authority bay DB-First and PacsUser by Code-First) are using Entity Framework ORM so
Why Code first doesn't know Authority primary key ?
Is there a way DbModelBuilder recognize primary keys automatically ?
Any Idea would be appreciated.
Primary Key Convention
Code First infers that a property is a primary key if a property on a class is named “ID” (not case sensitive), or the class name followed by "ID". If the type of the primary key property is numeric or GUID it will be configured as an identity column.
For example if you have following class
public class Department
{
// Primary key
public int DepartmentID { get; set; }
. . .
}
EF will use the DepartmentID as primary key, as alternative you could use Id Instead DepartmentID.
But your Authority class's key(AID) doesn't follow above convention. so you have to define custom mapping for it or change the AID to Id or AuthorityId.
You could see more default EF conventions here

EF Code First One-To-One with Join Table

I am trying to configure my model to an existing database, and am running into a problem. The previous developer modeled a one-to-one relationship using a join table. If I have the following classes and database structure below, how can I map this using code first?
public class Title {
public Property Property { get; set; }
}
public class Property {
public Title TitleInsurance { get; set; }
}
tbTitle
-TitleID = PK
tbPropertyToTitle
-TitleID - FK to tbTitle.TitleID
-PropertID - FK to tbProperty.PropertyID
tbProperty
-PropertyID = PK
Code in VB.Net here, but should be easy to translate. Mark primary keys with the Key data attribute. Entity Framework will automatically look for properties named Class + ID, i.e. tbTitleID to assign as primary keys, but since that isn't applicable here, we need the Key attribute.
Overridable properties denote Navigation Properties. In C#, this should be equivalent to Virtual properties. When this navigation property is accessed, Entity Framework will automatically look for valid foreign key relations, and populate the appropriate data.
For a one-to-one relationship, Entity Framework expects that your two tables share the same primary key, as shown by TitleID here.
Public Class tbTitle
<Key()>
Public Property TitleID As Integer
...
Public Overridable Property Property As tbProperty
End Class
Public Class tbProperty
<Key()>
Public Property TitleID As Integer
...
Public Overridable Property Title As tbTitle
End Class
Looking through the fluent API, I don't see any way to map one to one relations through a join table. You might be able to fake it by setting it up as a many to many but then you would need a bit of extra code to ensure that your relation collections only ever have one item in them.

How to refer to foreign key without HasForeignKey()

Using EF 4.0 with the 4.1 upgrade for POCO / code-first.
OK so I have a domain model where type Car has, in a collection, multiple objects of type Part. So a one:many relation.
HasMany(v => v.Parts)
.WithRequired()
.HasForeignKey(v => v.CarId)
.WillCascadeOnDelete();
The problem with this is that it requires me to add a CarId property to my Part type. This is leaking ORM detail into my domain model - which is bad. Marking everything virtual is annoying enough.
Looking at the XML doc comment for the HasForeignKey() method says this:
Configures the relationship to use
foreign key property(s) that are
exposed in the object model. If the
foreign key property(s) are not
exposed in the object model then use
the Map method.
That's great and all. But it introduces a catch-22 situation because if I refactor my Part type by removing the CarId property that I don't want and update my EF model builder to not bother with mapping that property. Then as you can imagine it means I cannot then call HasKey() for defining the composite key, ala:
HasKey(v => new { v.CarId, v.PartId });
HasKey() doesn't appear to support defining the keys based upon non-Property lambdas.
What is the solution here?
If you absolutely don't like to have foreign key properties in your model you could remove the convention to detect FK properties to avoid that EF marks properties automatically as FK properties ...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions
.Remove<NavigationPropertyNameForeignKeyDiscoveryConvention>();
}
... and then simply don't specify the FK property in your mapping:
HasMany(v => v.Parts)
.WithRequired()
.WillCascadeOnDelete();
You still need CarId in your model because it is part of the primary key, but this way it doesn't act anymore as foreign key property.
Just an idea, I am not sure if it works.
Well, what about adding a new key field to CarParts table like CarPartId, so you would not need the composite key. (Composite Key support is not that great when working with ORMs.)