Entity Framework table per type inheritance with PK->FK, not PK->PK - entity-framework

I have to create an entity framework model for a badly designed database. The database uses table per type inheritance but it does so with using a PK->FK relationship, not a PK->PK relationship. E.g.
Person
PersonID (PK)
Name
Employee
EmployeeID (PK)
PersonID (FK)
DateStarted
HourlyEmployee
HourlyEmployeeID (PK)
EmployeeID (FK)
HourlyRate
Obviously this is just badly designed, but I can't change it. Table per type inheritance in the entity framework essentially wants EmployeeID not to exist and the PK for Employee to be PersonID. Is it possible to create a model for this database, or do I choose another tool? any recommendations?

You will not map this as TPT inheritance because your database is configured in the way that doesn't allow you cheating EF.
If Employee.EmployeeID is auto-generated in the database and Employee.PersonID is unique (uniqueness must be enforced in the database) you should be able (not tested) to cheat EF by simply mapping:
public Employee : Person {
public DateTime DateStarted { get; set; }
}
This class will tell EF that Employee inherits key from Person (PersonID) and you will hide the real key from EF - this should work if the real key is auto-generated.
The problem is your next level of inheritance which breaks this pattern. To make this work your HourlyEmployee will have to reference PersonID - not EmployeeID. EF now doesn't know about EmployeeID existence so it even cannot map relation with HourlyEmployee.
TPT inheritance in code first has one additional limitation - PK column must have the same name in all tables.

You can create a model from the database if it exists but it might not be what you expect. EF sometimes doesn't work that great with weird database structures.

Related

Entity Framework 6 Database-First and Foriegn Key Naming Conventions

We've started using EF6 as part of rewriting our application suite. There are many perfectly reasonable tables in the existing suite and we're reusing them using a database-first approach. My problem is that EF6 seems to be enforcing what I think are code-first conventions on my database-first model.
Consider this minimal example with two tables defined thusly and appropriately populated with a few rows:
CREATE TABLE [dbo].[Table1] (
[Id] INT NOT NULL PRIMARY KEY,
[Table2Reference] INT NOT NULL REFERENCES [dbo].[Table2](Id) )
CREATE TABLE [dbo].[Table2] (
[Id] INT NOT NULL PRIMARY KEY,
[SomeColumn] NVARCHAR(25) )
After running Update Model From Database we get this model:
(Oops. Not enough reputation to post images. It's what you would imagine.)
So far so good, but when you write code to access the Table1 entity, like so...
var q = _context.Table1.ToList();
foreach (var item in q)
Debug.WriteLine("{0}", item.Table2Reference);
... it compiles fine but will throw on the ToList() line. This is because the SQL generated contains a request for a column that doesn't even exist:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Table2Reference] AS [Table2Reference],
[Extent1].[Table2_Id] AS [Table2_Id] <-- this one doesn't exist
FROM [dbo].[Table1] AS [Extent1]
I gather this has something to do with a code-first naming convention for foreign keys. I know I can rename Table2's Id column to Table2Id and rename Table2Reference to Table2Id and it will work. However, this is supposed to be database-first. Is there some way to tell EF to get out of the way and just go with what is actually in the pre-defined database? I did discover early on that I had to turn off the name pluralizing convention, but I can't seem to identify a convention to turn off that fixes this problem. I tried removing these:
modelBuilder.Conventions.Remove<PrimaryKeyNameForeignKeyDiscoveryConvention>();
modelBuilder.Conventions.Remove<TypeNameForeignKeyDiscoveryConvention>();
modelBuilder.Conventions.Remove<NavigationPropertyNameForeignKeyDiscoveryConvention>();
Anyway, I'm stumped. Is there an easy workaround that doesn't involve modifying the existing database?
Thanks for reading.
You can use data annotations attributes or fluent API to configure EF mapping to actual database tables. Here is how it can be done with attributes:
[Table("Table1")]
public class Table1
{
public int Id { get; set; }
public int Table2Reference { get; set; }
[ForeignKey("Table2Reference")]
public Table2 Table2 { get; set; }
}
It turns out that there is a very important piece to a database-first approach besides having an EDMX file. That is, your connection string must contain the following section:
metadata=res:///IPE.csdl|res:///IPE.ssdl|res://*/IPE.msl; (replacing IPE with the base name of your EDMX)
Otherwise, EF will be unable to locate the EDMX information in the assembly and code-first conventions can come into play. Mostly things just work, until they don't.

How to tell EntityFramework 5.0 that there's a one-to-one association between two entities?

I could go into the EDMX in design view and update the cardinality (1-, 0-, etc.) of associations, but I want to know if it is alright to do that in this scenario.
I have these two tables, let's say:
User
-----
Id
UserProfile
-------------
Id
UserId
Stuff
A single user may have just one profile. Therefore, I have set a UNIQUE constraint no the UserId column in the UserProfile table. Also, UserProfile.Id is defined as a foreign key that references User.Id.
However, in the Entity Framework model, I get the following:
class User
{
ICollection<UserProfile> UserProfiles { get; set; }
}
At first, I had the UserProfile table without any primary key of its own like this:
UserProfile
--------------
UserId
Stuff
But EntityFramework made that read-only as it needed to have a primary key on every table that you want to be made writable. So, I put an Id column in the UserProfile table as well.
UPDATE
I tried setting the multiplicit/cardinality of the association between the User table and the UserProfile table in my EDMX in the designer. However, I get this error suggesting I should turn it back to what it was, i.e. a one-to-many relationship.
Running transformation: Multiplicity is not valid in Role 'UserBasicProfile'
in relationship 'FK_UserBasicProfile_User'. Because the Dependent Role
properties are not the key properties, the upper bound of the multiplicity
of the Dependent Role must be *.
I've found a way. Well, not purely a 1-1 relationship but a 1-0..1 relationship was what I was after, which, for all practical purposes is a one-to-one relationship.
If you ever fall into this trap like I described in my question, here's what you do:
1) Remove the Id field from the dependent table, in this case the UserProfile table. Therefore, do not give it a separate primary key.
2) Instead, mark the foreign key in the dependent table as its own primary key. In this case, mark the UserId field itself as the primary key of the UserProfile table.
In addition to these two, I assume, as I outlined in the question that you've got a primary and foreign key relationship between the authority (the User table in this case) and the dependent table (the UserProfile table in this example).
So, you new table structure should look like this:
User
------
Id
UserProfile
-------------
UserId (foreign key, and also the primary key of this UserProfile table)
Stuff
Entity Framework will then recognize this 1-0..1 relationship.

Entity Framework - How to Insert to table with foreign keys without retrieving foreign table rows first

I'm having a hard time finding the exact answer to this question, so my apologies if this is redundant.
So I have 3 tables defined such that:
Person :PersonId, FirstName, LastName
Company: CompanyId, CompanyName
Order: OrderId, PersonId, CompanyId
On the Order table, there is a foreign key defined on the PersonId and CompanyId columns, thus, my Order entity class generated by EF has a navigation properties of type Person (not PersonId) and Company.
So, to insert into the Order table, I first need to query the person and company tables to get the person and company entities. Then I can construct the Order object using the Person and Company entities and save it to the db.
In my scenario, I am being passed a PersonId and CompanyId.
In classic SQL I would just do INSERT INTO Order Set (CompanyId, PersonId) - 1 database call. But with EF, I have to do 3 db calls. This seems like overkill.
Is there any way around this?
PS - I'm using EF 6. I know I could generate an expression and make it single call..but that would still yield two subselects.
You can just include foreign key properties in addition to the navigation properties and then set them using the ids you have. If you do this will not have to go to the database to get related entities for just a sake of setting the relationship.

Map tables relationship from legacy database w/ entity framework with only primary keys

data (table name)
dataid PK,
value1,
value2,
value3
data_address (table name)
dataaddressid PK,
dataid - id to errenddataid,
addressid1 - id to en addressid,
addressid2 - id to en addressid,
type
address (table namne)
addressid PK - id to addressid1 or addressid2,
address1,
address2,
name,
zipcode,
city
I have a really hard time trying to map this relations using Entity Framework 5, if some one have an idea or good links I would much appreciate that!
If you are certain that the database's integrity is sound you could just map the tables and create the associations manually in the EF model.
In a database-first mode I fiddled a bit with a simple data model: Parent + Child without FK. The tables were of course imported without association between them. Then I did "Add Association..." on the Parent, like so:
Note: no foreign key property yet. I added it manually in the properties of the association:
And I could run a linq query on Parent.Children.
I think this is the easiest way for you. The edmx design surface gives you some guidance to see which associations you created. You can always add a code generation item to generate a DbContext which is easiser to work with than the default ObjectContext.

Entity Framework Is it possible to add an ASSOCIATION between Primary Keys and a Foreign Key

I've got the following entities on my EDMX :-
These two entites were generated by Update Model From Database.
Now, notice how my country has the following primary key :-
Name & IsoCode
this is because each country is UNIQUE in the system by Name and IsoCode.
Now, with my States ... it's similar. Primary Key is :-
Name & CountryId
Each state is unique by name and per country.
Now, the Foreign Key for States is a CountryId. This is the sql :-
ALTER TABLE [dbo].[States] WITH CHECK ADD
CONSTRAINT [FK_States_Countries] FOREIGN KEY([CountryId])
REFERENCES [dbo].[Countries] ([CountryId])
ON UPDATE CASCADE
GO
ALTER TABLE [dbo].[States] CHECK CONSTRAINT [FK_States_Countries]
GO
Pretty simple stuff.
BUT EntityFramework doesn't like it :( It's assuming that i need to connect some properties from State entity to both primary key properties in the Country entity.
Is it possible to add an ASSOCIATION between Country and State on Country.CountryId <-> State.CountryId ... like i have mapped in my DB ?
Cheers ;)
In EF (3.5 and 4.0) FKs MUST point to Primary Keys.
But you appear to be attempting to point to a Candidate Key (i.e. [Countries].[CountryId]
I know that this is something the EF team are considering for the next version though :)
Hope this helps
Alex
For proper DB normalization, first thing is that primary keys must be only CountryId and StateId fields - the main Id fields for each table.
And ss I see from the description Name & IsoCode and Name & CountryId should be actually Unique keys, not primary.
Then the model class State should have a field:
public Country Country { get; set; }
Now EF have very good examples and since 4.3.1 + it fully supports Code first / DB first models, which I think will ease solving this.
EF 5 have more compatibility updates so I think it wont be a problem for legacy DB engines.