Entity Framework 7 - Central Table that joins to most tables - entity-framework

Let's say you have a table:
Document
-- DocumentId int PK
-- DocumentName varchar
-- EntityTypeId int
-- EntityId int
Also you have other business entities like House, Car, Boat, Motorcycle, etc that are entitytype with their own ids. Each one of them may have 0 or X documents.
How could you build this relationship in EF7, not sure it is possible, and/or how would you join this data in a query in EF.

Related

How can I implement this schema using EF code-first? [Complex Composite Key combinations (multiple foreign tables)]

We have an existing database which we'd like to connect to using code-first EF.
An issue we have come across is in the following scenario...
**TABLE 1**
DebtorID Int PK (identity column)
Type Int PK FK ( value would be '1' - FK to Table 4)
**TABLE 2**
CreditorID Int PK (identity column)
Type Int PK FK (value would be '2' - FK to Table 4)
**TABLE 3**
TransactionID Int PK
ParentID Int FK
ParentType Int FK
-----------------------
**TABLE 4**
Type Int PK (identity column)
Description Varchar(max)
Table 3 has foreign key links to multiple tables (Table 1, Table 2, etc...). The key is unique by the type column. Constraints have been altered here to allow this scenario.
Q. How can we implement this schema using code-first? We have looked at Data Annotations, and also Fluent API, but can't come up with a solution other than to alter the database schema (which would be a big headache).
As it stands, we only seem to be able to link to a single foreign table.
The solution also has to account for other tables (not shown here) where the primary keys for Table 1 etc... are part of the primary key.
A real world view of our schema, and the issue with code-first.
Current schema:
http://oi60.tinypic.com/2aeug4m.jpg
Code-First schema:
http://oi62.tinypic.com/9schmc.jpg
I have found the answer using the Fluent Api - was much easier than I thought.
Simply in the OnModelCreating() method, I needed to add multiple ForeignKey entries to cover each link.
modelBuilder.Entity(Of TABLE_3).HasRequired(Function(p) p.TABLE_1).WithMany().HasForeignKey(Function(p) New With {p.ParentID, p.ParentType})
modelBuilder.Entity(Of TABLE_3).HasRequired(Function(p) p.TABLE_2).WithMany().HasForeignKey(Function(p) New With {p.ParentID, p.ParentType})
This was in addition to any configuration I did using Data Annotation with regards to setting up primary keys and navigational properties (e.g. navigation properties for TABLE_1 and TABLE_2)

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.

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

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.

What 'possible data inconsistency' is entity framework worried about in a 'foreign key participating in multiple relationships' situation?

Suppose the following database schema:
Table A: AId (PK)
Table B: BId (PK)
Table C: CId (PK)
Table AB: AId, BId (composite PK, FKs to A and B), Data
Table BC: BId, CId (composite PK, FKs to B and C), Data
Table ABC: AId, BId, CId, Data
In the database, ABC has two FKs: one to AB on AId and BId, and one to BC on BId and CId.
Use the EF Designer and attempt to create a Model from this database.
If you have Include foreign key columns in the model checked, it works; but having FK Columns in the model isn't very nice.
If you have Include foreign key columns in the model unchecked, only one of the FKs from ABC will be successfully mapped. To see what went wrong, you have to view the .edmx xml (thanks Craig!) and you see this error:
warning 6037: Foreign key constraint 'FK_ABC_BC' has been omitted from the storage model. Column 'BId' of table 'Model.Store.ABC' is a foreign key participating in multiple relationships. A one-to-one Entity Model will not validate since data inconsistency is possible.
I've read the only other mention of this problem I can find on SO, and I don't think this is the same problem. I can't see anything wrong at a database design level. I'm going to work round this for the time being by imposing surrogate keys on AB and BC, but what I'd really like to know is:
What possible data inconsistency is EF worried about happening here, if it created a model to match the database?
And is there anything I can do to persuade it that everything's going to be OK?
My opinion is that EF is too clever in this scenario and it prevents you from using entity where you can assign only one relation and make the entity non-savable because relation to second entity will not exists.
There is also possibility that EF has some internal problem with tracking state of independent associations if more than one association is based on the same foreign key column but that is just another guess. Generally database features used to map EF features cannot be shared among multiple constructions. The only exceptions I can think about now are primary keys and in their own way discriminator columns.
I would like to mention that I don't like this type of relations in database at all.

Many-to-Many Relationships in EF4 with "Shared" columns

Disclaimer: Strictly speaking, what I have here is not a many-to-many relationship, but given that it's using an associative table, I figured it would be better to be slightly less accurate in order to give a better idea of what I'm doing.
I have the equivalent of the following three tables in my database:
Customer
---------
CustomerID PK
...
CustomerAddress
---------
CustomerID PK, FK -> Customer
AddressNo PK
... address columns ...
CustomerPrimaryAddress
--------------
CustomerID PK, FK -> Customer
AddressNo FK -> CustomerAddress (with CustomerID, so CustomerID
participates in both relationships)
If it's not obvious, the intent here is to allow for multiple addresses per customer, while designating at most one address per customer as "primary". I'm using an associative table to avoid placing a nullable PrimaryAddressNumber column on Customer, then creating a foreign key from Customer to CustomerAddress.
This is all well and good, but EF then places the CustomerPrimaryAddress entity in my model. Since its one and only purpose is to serve as an associative table, I have no need to represent this table in code. I removed the CustomerPrimaryAddress table from the conceptual model, then created an association between Customer and CustomerAddress like so:
Table Customer CustomerAddress
Multiplicity 1 0..1
I then mapped the association to use the CustomerPrimaryAddress table from the storage model, and all of the columns mapped just fine, or so I thought.
My issue is that now EF is complaining that CustomerID in CustomerPrimaryAddress is being mapped to two locations in my association, as it's mapped to both Customer and CustomerAddress.
Is there any way around this? I would prefer not to add a nullable column to Customer to represent the primary address number, as not only is this not a pleasant option from a DBA perspective, EF will also complain about having a cyclical relationship and I'll have to break inserts up in the code.
Thinking out loud here:
Customer
---------
CustomerID PK
...
CustomerAddress
---------
AddressNo PK
CustomerID FK -> Customer, non-nullable
... address columns ...
CustomerPrimaryAddress
--------------
CustomerID PK, FK -> Customer
AddressNo FK -> CustomerAddress
This seems like it should get the cardinalities right, but I may have missed something.