Entity Framework - Join table with composite key and a primary key - entity-framework

I am struggling with the way entity framework handles join tables, specifically because entity framework requires that a join table has a composite key composed of the primary keys on the two related entities I want the hold the relationship for. The problem here is that I need to hold a relationship to the relationship so to speak.
This may be a problem with my database design or equally due to my lack of understanding with EF. It is probably best illustrated through example (see below);
I have three tables each with a primary key:-
Table : DispatchChannel
{ *DispatchChannelID integer }
Table : Format
{ *FormatID integer }
Table : EventType
{ *EventTypeID integer }
The relationship between EventTypes and DispatchChannels is held in EventTypeDispatchChannels (see below) since this only contains a composite key it is not pulled through into our model and entity framework takes care of maintaining the relationship.
Table : EventTypeDispatchChannels
{ EventTypeID integer, DispatchChannelID integer
}
My problem now arises because for each combination of EventTypeID and DispatchChannelID I want to hold a list of available formats, this would be easy if my EventTypeDispatchChannels table had a primary key therefore my other join table would look like this;
Table : EventTypeDispatchChannelFormats
{ EventTypeDispatchChannelID integer, FormatID integer
}
The absence of a primary key on EventTypeDispatchChannels is where I am struggling to make this work, however if I had the key then entity framework no longer sees this as a linked entity.
I'm relatively new to C# so apologies if I have not explained this so well, but any advice would be appreciated.

The moment you want to give an association a more important role than just being a piece of string between two classes, the association becomes a first-class citizen of your domain and it's justified to make it part of the class model. It's also inevitable, but that's secondary.
So you should map EventTypeDispatchChannels to a class. The table could have its own simple primary key besides the two foreign keys. A simle PK is probably easier, so your table Format can do with a simple foreign key to EventTypeDispatchChannels for the one-to-many association.
You will lose the many to many feature to simply address dispatchChannel.Events. In stead you have to do
db.DispatchChannels.Where(d => d.DispatchChannelID == 1)
.SelectMany(d => d.EventTypeDispatchChannels)
.Select(ed => ed.Event)
On the other hand you have gained the possibility to create an association by just creating an EventTypeDispatchChannel and setting its primitive foreign key values. Many-to-many associations with a transparent junction table can only be set by adding objects to a collection (add an Event to dispatchChannel.Events). This means that the collection must be loaded and you need an Event object, which is more expensive in database round trips.

Related

Database design with composite types in postgresql

How to refer another table built from composite type in my table.
I am trying to setup a database to understand postgresql and its Object oriented features.
The statement is as follows : There are multiple companies which can have board members.
Each company can own another company or a person can own that company too.
This is the type of database design I am looking for.
create type companyType(
name: VARCHAR,
boardMembers : personType[],
owns: companyType[]
)
create type personType(
name: VARCHAR,
owns: companyType[]
)
Create table company as companyType
Create table person as personType
I understand that I cannot self reference the companyType so I will probably move this another table.
My question is, when I am trying to insert into say company type, how do i insert list of person table objects as foreign key ?
Would making a column 'id' in each table and giving it type SERIAL work to use it as a foreign key?
That is not a relational database design, and you won't get happy with it.
Map each object to a table. The table columns are the attributes of the object. Add an artificial primary key (id bigint GENERATED ALWAYS AS IDENTITY). Don't use composite types or arrays.
Relationships are expressed like this:
If the relationship is one-to-many, add a foreign key to the "many' side.
If the relationship is many-to-many, add a "junction table" that has foreign keys to both tables. The primary key is the union of these foreign keys.
Normalize the resulting data model to remove redundancies.
Sprinkle with unique and check constraints as appropriate.
That way your queries will become simple, and you can use your database's features to make your life easier.

Entity Framework and multi-tenancy database design

I am looking at multi-tenancy database schema design for an SaaS concept. It will be ASP.NET MVC -> EF, but that isn't so important.
Below you can see an example database schema (the Tenant being the Company). The CompanyId is replicated throughout the schema and the primary key has been placed on both the natural key, plus the tenant Id.
Plugging this schema into the Entity Framework gives the following errors when I add the tables into the Entity Model file (Model1.edmx):
The relationship 'FK_Order_Customer' uses the set of foreign keys '{CustomerId, CompanyId}' that are partially contained in the set of primary keys '{OrderId, CompanyId}' of the table 'Order'. The set of foreign keys must be fully contained in the set of primary keys, or fully not contained in the set of primary keys to be mapped to a model.
The relationship 'FK_OrderLine_Customer' uses the set of foreign keys '{CustomerId, CompanyId}' that are partially contained in the set of primary keys '{OrderLineId, CompanyId}' of the table 'OrderLine'. The set of foreign keys must be fully contained in the set of primary keys, or fully not contained in the set of primary keys to be mapped to a model.
The relationship 'FK_OrderLine_Order' uses the set of foreign keys '{OrderId, CompanyId}' that are partially contained in the set of primary keys '{OrderLineId, CompanyId}' of the table 'OrderLine'. The set of foreign keys must be fully contained in the set of primary keys, or fully not contained in the set of primary keys to be mapped to a model.
The relationship 'FK_Order_Customer' uses the set of foreign keys '{CustomerId, CompanyId}' that are partially contained in the set of primary keys '{OrderId, CompanyId}' of the table 'Order'. The set of foreign keys must be fully contained in the set of primary keys, or fully not contained in the set of primary keys to be mapped to a model.
The relationship 'FK_OrderLine_Customer' uses the set of foreign keys '{CustomerId, CompanyId}' that are partially contained in the set of primary keys '{OrderLineId, CompanyId}' of the table 'OrderLine'. The set of foreign keys must be fully contained in the set of primary keys, or fully not contained in the set of primary keys to be mapped to a model.
The relationship 'FK_OrderLine_Order' uses the set of foreign keys '{OrderId, CompanyId}' that are partially contained in the set of primary keys '{OrderLineId, CompanyId}' of the table 'OrderLine'. The set of foreign keys must be fully contained in the set of primary keys, or fully not contained in the set of primary keys to be mapped to a model.
The relationship 'FK_OrderLine_Product' uses the set of foreign keys '{ProductId, CompanyId}' that are partially contained in the set of primary keys '{OrderLineId, CompanyId}' of the table 'OrderLine'. The set of foreign keys must be fully contained in the set of primary keys, or fully not contained in the set of primary keys to be mapped to a model.
The question is in two parts:
Is my database design incorrect? Should I refrain from these compound primary keys? I'm questioning my sanity regarding the fundamental schema design (frazzled brain syndrome). Please feel free to suggest the 'idealized' schema.
Alternatively, if the database design is correct, then is EF unable to match the keys because it perceives these foreign keys as a potential mis-configured 1:1 relationships (incorrectly)? In which case, is this an EF bug and how can I work around it?
On a quick scan of EF's error messages, it clearly doesn't like the way you're setting up compound keys, and I think it's probably nudging you in the right direction. Give some thought again to what makes your primary keys unique. Is the OrderID alone not unique, without a CompanyID? Is a ProductID not unique, without a CompanyID? An OrderLine certainly should be unique without a CompanyID, since an OrderLine should be associated only with a single Order.
If you truly need the CompanyID for all of these, which probably means that the company in question is supplying you with ProductID and OrderID, then you might want to go a different direction, and generate your own primary keys that are not intrinsic to the data. Simply set up an auto-increment column for your primary key, and let these be the internal OrderID, OrderLineID, ProductID, CompanyID, etc. At that point, the OrderLine won't need the customer's OrderID or CompanyID; the foreign key reference to the Order would be its starting point. (And the CustomerID should never be an attribute of an order line; it's an attribute of the order, not the order line.)
Compound keys are just messy. Try designing the model without them, and see if it simplifies things.
I think that the error is not in the design.
Is not in the EF.
Is in Sql Server relations.
Read the EF message:
The relationship 'FK_Order_Customer'
uses the set of foreign keys
'{CustomerId, CompanyId}' that are
partially contained in the set of
primary keys '{OrderId, CompanyId}' of
the table 'Order'. The set of foreign
keys must be fully contained in the
set of primary keys, or fully not
contained in the set of primary keys
to be mapped to a model.
ERROR
Actualy the relation betwen Order and Customer use only one field (probably you dragged with the mouse the field "CustomerId" from teh Order table to the "Id" of the Customer table)
SOLUTION
Right click on the wire that connect Order and Customer and in the relation add also the CompanyId
PS: The design is correct.
Putting the CompanyId in each table is rith solution in multi-tenant architecture because help to scale (usualy always want to select only records from the loggedIn company).
I think storing the company number in each of the tables is hurting you more than helping. I can understand why you want to do this (as the programmer/dba you can just go into any table and 'see' what data belongs to who which is comforting), but it is getting in the way of you setting up the database the way it should be.
Avoid the compound keys and your design gets a whole lot simpler.
If you have to absolutely add CompanyID column to each table, add it as a regular column and not a composite Key. Composite key is mostly used when you have to implement many to many relationship.
As someone mentioned also create a Non-clustered Index on CompanyID so joins to the Company table are benefitted.
Thanks!
First: like others said, when referencing a foreign key, use the whole primary key in the other table (ie. both fields).
Second, I cannot imagine not using a CompanyID column in most tables in a serious application. Orderdetail might perhaps be an exception in this case (also global lookup tables perhaps, unless they are tenant dependant). Thing is, you cannot do any safe sort of free form search on a table without either adding the CompanyID, or doing JOINs up until the point you reach a table which has that column. The latter one obviously costs performance. Perhaps in this case you could make an exception for orderdetail and only search in the joined version (only two tables). Then again, its not really consistent.
Also regarding making a it a compound key or not: its possible, but opens up the possibility that a bug writes information incorrectly (into non existent, or other people's administrations) for the duration of the bug. Try to fix that in production, not to mention explain it to customers why there are seeing their competitors orders in their system.

Entity Framework Association with Non Key fields

Is it possible to create associates b/t 2 non-key fields in the Entity Framework?
Example: Take the 2 tables in a legacy application (i.e. keys/structure cannot change)
Order (
OrderId : int : PK
OrderNo : varchar
)
OrderDetails (
DetailRecordId : int : PK
OrderNo : varchar
)
In the Entity Framework, I want to create an association b/t Order and OrderDetails by the OrderNo field, which is not a primary key on either table or a FK relationship in the database.
This seems to me as not only should it be easy to do, but one reasons to use something like EF. However, it seems to only want to allow me to create associations using entity keys.
The Entity Framework allows you to claim that columns are keys and that FK constraints exist where none actually exist in the database.
That is because the SSDL (StorageModel part of the EDMX) can if necessary be manipulated by you and lie about the database.
The EF will then interact with the database as if the keys and foreign keys really do exist.
This should work, but all the normal caveats about referential integrity apply.
See my Entity Framework Tips
Hope this helps.
The problem with using non-key fields to define relationships is that the keys are not guaranteed to be properly navigatable. That could lead to a situation where you have a one to one relationship between two entities where there are more than one possible rows that fufill the relationship.
...when relating data from a database, the relationships should always be based on keys. The keys enforce the referential integrity.
One more workaround:
create view vOrder which will not include PK and create Entity from it.
Set PK in this entity to OrderNo
Now you will be able create association

E2L: How do you handle Foreign Keys that participate in multiple relationships?

I have a Database model like this
FlowObject
FlowObjectID (PK)
Description
Active
ProcessObject
FlowObjectID (PK, FK)
HasSubmit
DecisionObject
FlowObjectID (PK, FK)
YesFlowObjectID (FK)
NoFlowObjectID (FK)
YesCaption
NoCaption
When I try and use create my Entity model I get this warning in my project.
Foreign Key constraint 'FK_ProcessObject_FlowObject1' has been omitted from the storage model. Column 'FlowObjectID' of table 'Investigations.Store.ProcessObject' is a Foreign Key participating in multiple relationships. A one-to-one Entity Model will not validate since data inconsistency is possible.
???
Why did it drop my foreign key? Because "A one-to-one Entity Model will not validate since data inconsistency is possible."
So it sounds like it is saying it dropped the FK because of data inconsistency but dropping the FK actually reduces date consistency?
Should I redesign my database? Is there anyway for L2E to handle FK's that participate in multiple relationships? Is it considered bad database design to have FK's that participate in multiple relationships?
What you've described, translated to object-oriented terms, is that a FlowObject contains an optional ProcessObject and an optional DecisionObject. If this is what you actually meant, the database schema is correct.
If you're trying to have ProcessObject and DecisionObject extend FlowObject, inconsistency is possible because both the ProcessObject and DecisionObject rows may exist. To eliminate the inconsistency, the union-subclass modeling technique is appropriate: only ProcessObject and DecisionObject tables exist, each containing all relevant fields, and FlowObject, as an abstract base class, becomes a view consisting of the union of the common base fields between the two tables.
I have just get the same error when trying to refactor this. In EFv1 (.NET 3.5) this cannot be solved. In EFv4 (.NET 4.0) you can change independent association (the only association/relation available in EFv1) to foreign key association and it will work. But FK associations have some other drawbacks so it is not a silver bullet.

How to handle "secondary" keys in Entity Framework

I'm evaluating using EF against an existing schema - the problem is that I can't work out how to set up associations between tables where the foreign key is NOT the primary key of the master table.
As an example, a foo may have many bars as defined like this (forgive the pseudocode):
table foo {
int foo\_id pk,
char(10) foo\_code,
...
}
table foobar {
int bar\_id pk,
char(10) bar\_foo\_code fk(foo.foo\_code),
...
}
What am I missing to be able to create the foo_foobar association, and hence a Bars navigation property on the Foo entity?
Linq to entities doesn't support Foreign Keys which don't point to the primary key of a table (see log message 3). Linq to entities will treat it as a normal field on a table. You won't be able to navigate to the entity it's linked to.
If you have an existing schema i'd recommend using the edm generator as this will create the EMDX file, code behind and even the view code (which can be very large). If your existing scheme is quite large Check out this post, which explains how to deal with large schemas.
When you run the EDM Generator you'll find out all the things that are not supported.
Looking at a previous EDMGen2.exe log we got the following types of messages back:
The data type 'sql_variant' is not
supported, the column 'ColumnName'
in table 'TableName' was
excluded.
The table/view 'tableName' does not
have a primary key defined. The key
has been inferred and the definition
was created as a read-only table/view
The relationship 'RelationshipName'
has columns that are not part of
the key of the table on the
primary side of the relationship
which is not supported, the
relationship was excluded.
We've also found that the Linq project actually crashed Visual Studio quite alot as the code file produced by EDM was well over 80 mb.