I'm working on a new project and ran into an issue with EF Core 7
It's a fairly simple situation so there must be an easy solution but I'm just stuck. Here's the situation.
A Customer has many addresses. So far so easy - just add an CustomerID column to Address and EF does it's magic and sets up the foreign key.
..but then a customer might want to save the default address among their many addresses. This is also easy at first. A DefaultAddressID? nullable Property in Customer links to an address record. The potential problem here is that the database is not guaranteeing that the Address referenced by the DefaultAddressID? property also has a CustomerID that references back to the customer. In theory a customer could be set up so that somebody else's address is their default address. That's where I'm stuck.
I need a composite foreign key so that a customer can only have one of their own addresses as a default address.
In raw SQL this is pretty easy:
alter table Customers
Add constraint FK_Customer_DefaultBilltoAddress
foreign Key(DefaultBilltoAddressID,ID)
references Addresses(ID,CustomerID)
I've tried to replicate this in EF any number of ways but I haven't had any luck.
modelBuilder.Entity<Customer>()
.HasOne(c => c.DefaultBillToAddress)
.WithOne()
.HasForeignKey(nameof(Address),new string[] {nameof(Customer.ID),nameof(Customer.DefaultBillToAddressID)})
.HasPrincipalKey(nameof(Customer),new string[] {nameof(Address.CustomerID),nameof(Address.ID) })
.OnDelete(DeleteBehavior.NoAction);
I tried all kinds of options and nothing seems to make EF happy.
Related
I'm evolving here and making progress it appears. Last week I'd posted a question and gotten some responses that made although they didn't give me an answer did make me question some of the things that I had tried and made me go back to rework some configurations of my database tables a bit to see if that would prove to be more conducive to the EF approach which as I've mentioned is entirely new to me coming back to web development after being way for many years.
I tried several different things including some foreign key options but because I'm dealing with larger 1 to many relationships that was going to be problematic as well. As it ended up it flat out wasn't working. My last attempt was this morning when I restructured the tables to include all fields that were included in my associations inside the primary keys of the four tables.
I then re-created the EF Data Model for the project and built associations for each of the tables linking ONLY the fields values that were valid for the link between each of the associations. This mean that in some cases as you'll see below some elements of a tables key were left without matches assigned to them. I wasn't sure if I could get away with this or not. But to my surprise I was successful in establishing an association between all of the tables as I had intended for the first time since starting this project. I'm attaching the model diagram here though I doubt it will be helpful for this discussion. EF Data Model
Now, I may be okay or I may still be in the weeds. I will et you experts tell me how I stand here. The result of this is that I've pulled up two new errors repeated twice. One set of errors for the association between GETT_Family_Group_List and GETT_Elements tables and the other is for the association between GETT_Elemenets and GETT_Documents tables. Virtually the same issue so I'm only going to talk about the first one and not the second one, because, if and when we come up with a solution for the first that should apply to the second as well. here are the two errors that I'm getting for each of these:
Error 111: Properties referred by the Principal Role
GETT_Family_Group_List must be exactly identical to the key of the
EntityType ARFSModel. GETT_Family_Group_List referred to by the
Principal Role in the relationship constraint for Relationship
ARFSModel.GETF_Family_GroupjistGErf_Elements. Make sure all the key
properties are specified in the Principal Role.
Running transformation: Properties referred by the Principal Role
GETT_Family_Group_List must be exactly identical to the key of the
EntityType ARFSModel.GETT_Family_Group_List referred to by the
Principal Role in the relationship constraint for Relationship
ARFSModel.GETT_Family_Group_ListGETI_Elements. Make sure all the key
properties are specified in the Principal Role.
The tables layouts related to these two tables that are pulling these two errors as well as the Referential Constraint look like this: Tables and Constraints
That's about it... I supplied you with about all I can think of. Let me know if you need more and I will try to provide it.
Thanks and regards,
Ken...
EDITED:
Properties
ARFSModel.GETT_Family_Group_ListGETT_Element Association
- Constraints
Referential Contraint GETT_Family_Group_List -> GETT_Elements
- General
Association Set Name Gett_Family_Group_ListGET_Elements
- Documentation
Long Description
Summary
End1 Multiplicity 1 (One of GET_Family_Group_List)
End1 Navigation Property GETT_Elements
End1 OnDelete None
End1 RoleName GETT_Family_Group_List
End2 Multiplicity * (collection of GETT_Elements)
End2 Navigation Property) GETT_Family_Group_List
END2 OnDelete None
End2 Role Name GETT_Elements
Name GETT_Family_Group_ListGETT_Elements
Hopefully this is more readable!
Regards,
Ken...
I have been asked to add a new address book table to our database (SQL Server 2012).
To simplify the related part of the database, there are three tables each linked to each other in a one to many fashion: Company (has many) Products (has many) Projects and the idea is that one or many addresses will be able to exist at any one of these levels. The thinking is that in the front-end system, a user will be able to view and select specific addresses for the project they specify and more generic addresses relating to its parent product and company.
The issue now if how best to model this in the database.
I have thought of two possible ideas so far so wonder if anyone has had a similar type of relationship to model themselves and how they implemented it?
Idea one:
The new address table will additionally contain three fields: companyID, productID and projectID. These fields will be related to the relevant tables and be nullable to represent company and product level addresses. e.g. companyID 2, productID 1, projectID NULL is a product level address.
My issue with this is that I am storing the relationship information in the table so if a project is ever changed to be related to a different product, the data in this table will be incorrect. I could potentially NULL all but the level I am interested in but this will make getting parent addresses a little harder to get
Idea two:
On the address table have a typeID and a genericID. genericID could contain the IDs from the Company, Product and Project tables with the typeID determining which table it came from. I am a little stuck how to set up the necessary constraints to do this though and wonder if this is going to get tricky to deal with in the future
Many thanks,
I will suggest using Idea one and preventing Idea two.
Second Idea is called Polymorphic Association anti pattern
Objective: Reference Multiple Parents
Resulting side effect: Using dual-purpose foreign key will violating first normal form (atomic issue), loosing referential integrity
Solution: Simplify the Relationship
The simplification of the relationship could be obtained in two ways:
Having multiple null-able forging keys (idea number 1): That will be
simple and applicable if the tables(product, project,...) that using
the relation are limited. (think about when they grow up to more)
Another more generic solution will be using inheritance. Defining a
new entity as the base table for (product, project,...) to satisfy
Addressable. May naming it organization-unit be more rational. Primary key of this organization_unit table will be the primary key of (product, project,...). Other collections like Address, Image, Contract ... tables will have a relation to this base table.
It sounds like you could use Junction tables http://en.wikipedia.org/wiki/Junction_table.
They will give you the flexibility you need to maintain your foreign key restraints, as well as share addresses between levels or entities if that is desired.
One for Company_Address, Product_Address, and Project_Address
I'm trying to use EF to model an existing SQL database. The DB is multi-tenant by having a clientID column in every single table (I cannot change this). I have table structure like the following.
Table 'ItemID' columns:
ClientID (pk)
ItemID (pk)
ItemName
Table 'Items' columns:
ClientID (PK)
ItemID (PK) [FK to ItemID.ItemID]
Version (PK)
ItemAttribute1
ItemAttribute2
ItemAttribute3
The DB is designed to store previous versions (rows) of the 'Item' object, hence the 'Version' column and PK.
I am new to the EF and trying to adopt it for my project. However, it seems that EF cannot handle this situation very well. I am open to all ideas including using stored procedures or views instead of access tables directly from EF. What about getting rid of the PKs and using 'independant' relations instead?
One specific problem I ran into is that EF (at least the designer) requires all PKs in one table be mapped to all PK columns in any related table. This does not make sense to me, as the example I've given will never work given that constraint. I am trying to make Items inherit from ItemID. The error I get is:
Error 3003: Problem in mapping
fragments starting at line 170:All the
key properties (ItemID.ClientID,
ItemID.ItemID) of the EntitySet ItemID
must be mapped to all the key
properties (Items.ClientID,
Items.ItemID, Items.Version) of table
Items.
I have been looking up all I can find on this topic and nothing has answered these questions for me. I appreciate any help. Thanks.
The error that you are getting from your EDM is coming from the fact that EF supports inheritance only if both entities have the exact same primary keys (hence a one to one relationship on database) so you cannot have inheritance between these 2 entities according to the current schema.
However, I don't see a problem on having a One to Many association between ItemID and Items entities and I believe this is the default EF behavior when you update your model from the database.
Please have a look at this post for more info:
Entity Framework, TPT Inheritance
I'm working on a multi-user internet database-driven website with SQL Server 2008 / LinqToSQL / custom-made repositories as the DAL. I have run across a normalization problem which can lead to an inconsistent database state if exploited correctly and I am wondering how to deal with the problem.
The problem: Several different companies have access to my website. They should be able to track their Projects and Clients at my website. Some (but not all) of the projects should be assignable to clients.
This results in the following database schema:
**Companies:**
ID
CompanyName
**Clients:**
ID
CompanyID (not nullable)
FirstName
LastName
**Projects:**
ID
CompanyID (not nullable)
ClientID (nullable)
ProjectName
This leads to the following relationships:
Companies-Clients (1:n)
Companies-Projects (1:n)
Clients-Projects(1:n)
Now, if a user is malicious, he might for example insert a Project with his own CompanyID, but with a ClientID belonging to another user, leaving the database in an inconsistent state.
The problem occurs in a similar fashion all over my database schema, so I'd like to solve this in a generic way if any possible. I had the following two ideas:
Check for database writes that might lead to inconsistencies in the DAL. This would be generic, but requires some additional database queries before an update and create queries are performed, so it will result in less performance.
Create an additional table for the clients-Projects relationship and make sure the relationships created this way are consistent. This also requires some additional select queries, but far less than in the first case. On the other hand it is not generic, so it is easier to miss something in the long run, especially when adding more tables / dependencies to the database.
What would you do? Is there any better solution I missed?
Edit: You might wonder why the Projects table has a CompanyID. This is because I want users to be able to add projects with and without clients. I need to keep track of which company (and therefore which website user) a clientless project belongs to, which is why a project needs a CompanyID.
I'd go with with the latter, having one or more tables that define the allowable relationships between entities.
Note, there's no circularity in the references you have, so the title is misleading.
What you have is the possibility of conflicting data, that's different.
Why do you have "CompanyID" in the project table? The ID of the company involved is implicitly given by the client you link to. You don't need it.
Remove that column and you've removed your problem.
Additionally, what is the purpose of the "name" column in the client table? Can you have a client with one name, differing from the name of the company?
Or is "client" the person at that company?
Edit: Ok with the clarification about projects without companies, I would separate out the references, but you're not going to get rid of the problem you're describing without constraints that prevent multiple references being made.
A simple constraint for your existing tables would be that not both the CompanyID and ClientID fields of the project row could be non-null at the same time.
If you want to use the table like this and avoid the all the new queries just put triggers on the table and when user tries to insert row with wrong data the trigger with stop him.
Best Regards,
Iordan
My first thought would be to create a special client record for each company with name "No client". Then eliminate the CompanyId from the Project table, and if a project has no client, use the "No client" record rather than a "normal" client record. If processing of such no-client's is special, add a flag to the no-client record to explicitly identify it. (I'd hate to rely on the name being "No Client" or something like that -- too fuzzy.)
Then there would be no way to store inconsistent data so the problem would go away.
In the end I implemented a completely generic solution which solves my problem without much runtime overhead and without requiring any changes to the database. I'll describe it here in case someone else has the same problem.
First off, the approach only works because the only table that other tables are referencing through multiple paths is the Companies table. Since this is the case in my database, I only have to check whether all n:1 referenced entities of each entity that is to be created / updated / deleted are referencing the same company (or no company at all).
I am enforcing this by deriving all of my Linq entities from one of the following types:
SingleReferenceEntityBase - The norm. Only checks (via reflection) if there really is only one reference (no matter if transitive or intransitive) to the Companies table. If this is the case, the references to the companies table cannot become inconsistent.
MultiReferenceEntityBase - For special cases such as the Projects table above. Asks all directly referenced entities what company ID they are referencing. Raises an exception if there is an inconsistency. This costs me a few select queries per CRUD operation, but since MultiReferenceEntities are much rarer than SingleReferenceEntities, this is negligible.
Both of these types implement a "CheckReferences" and I am calling it whenever the linq entity is written to the database by partially implementing the OnValidate(System.Data.Linq.ChangeAction action) method which is automatically generated for all Linq entities.
I am building a database as a simple exercise, it could be hosted on any database server, so I am trying to keep things as much standard as possible. Basically what I would like to do is a 'code' table that get referenced by other entities. I explain:
xcode
id code
r role
p property
code
r admin
r staff
p title
....
then I would like to have some view like:
role (select * from code where xcode='r')
r admin
r staff
property (select * from code where xcode='p')
p title
then, suppose we have an entity
myentity
id - 1
role - admin (foreign key to role)
title - title (foreign key to property)
Obviously I cannot create foreign key to a view, but this is to tell the idea I have in mind. How can I reflect such behaviour using whenever possible, standard sql syntax, then as a second option, database additional features like trigger ecc... ?
Because if I tell that role and title in myentity are foreign key to 'code', instead of the views, nothing would stop me to insert a role in title field.
I have worked on systems with a single table for all codes and others with one table per code. I definitely prefer the latter approach.
The advantages of a table per code are:
Foreign keys. As you have already spotted it is not possible to enforce compliance to permitted values through foreign keys with a single table. Using check constraints is an alternative approach but it has a higher maintenance cost.
Performance. Code lookups are not normally a performance bottle neck, but it undoubtedly helps the optimizer to make sensible decisions about execution paths if it knows it is retrieving records from a table with four rows rather than four hundred.
Code groups. Sometimes we want to organise a code into sub-divisions, usually to make it easier to render complex lists of values. If we have a table per code we have more flexibility when it comes to structure.
In addition I notice that you want to be able to deploy "on any database server". In that case avoid triggers. Triggers are usually bad news in most scenarios, but they have product-specific syntax.
What you are trying to do is in most cases an anti pattern and design mistake. Just create the different tables instead of views.
There are some rare cases where this kind of design makes sense. In this kind include the xcode field in the primary key/ foreign key. So your entity will look like this:
myentity
id - 1
role_xcode
role - admin (foreign key to role)
title_xcode
title - title (foreign key to property)
You then can create check constraints to enforce role_xcode='r' and title_xcode='p'
(sorry I don't know if they are standard, they do exist in oracle and are so simple that I'd expect them on other rdbms's as well)