Foreign Key to non-primary key
If you really want to create a foreign key to a non-primary key, it MUST be a column that has a unique constraint on it.
From Books Online:
A FOREIGN KEY constraint does not have to be linked only to a PRIMARY
KEY constraint in another table; it can also be defined to reference
the columns of a UNIQUE constraint in another table.
So in your case if you make AnotherID
unique, it will be allowed. If you can't apply a unique constraint you're out of luck, but this really does make sense if you think about it.
Although, as has been mentioned, if you have a perfectly good primary key as a candidate key, why not use that?
can we have a foreign key which is not a primary key in any other table?
Yes - you can have a foreign key that references a unique index in another table.
CREATE UNIQUE INDEX UX01_YourTable ON dbo.YourTable(SomeUniqueColumn)
ALTER TABLE dbo.YourChildTable
ADD CONSTRAINT FK_ChildTable_Table
FOREIGN KEY(YourFKColumn) REFERENCES dbo.YourTable(SomeUniqueColumn)
Is it possible to set a non primary key as foreign key in another table?
Yes and No
SQL Server, specifically:
If you're just asking about SQL Server (and not Entity Framework), then I quoteth Microsoft's documentation:
A foreign key constraint doesn't have to be linked only to a primary key constraint in another table. Foreign keys can also be defined to reference the columns of a UNIQUE constraint in another table.
Therefore to answer your stated question directly:
- Is it possible to set a non primary key as foreign key in another table?
- If they're "normal" columns, then no, because otherwise SQL Server has no way of knowing that those values will uniquely identify each row.
- But if the columns are in either in a
UNIQUE CONSTRAINT
or have a non-filteredUNIQUE INDEX
applied to them, then yes, you can. - This requires SQL Server 2005 or later. (I might be wrong, but I don't believe SQL Server 2000 supported
FOREIGN KEY
constraint columns referencingUNIQUE CONSTRAINT
columns.
There are subtle differences between UNIQUE CONSTRAINT
and UNIQUE INDEX
, though the main difference is indicating intent - so you should prefer UNIQUE CONSTRAINT
over UNIQUE INDEX
when you're using a column - or columns - as a secondary key.
Entity Framework
Entity Framework 6:
- I'll admit I'm unsure. I remember having to really fight EF6 and use workarounds like
VIEW
s to make EF6 play-nice with FK references toUNIQUE KEY
constraints, but some reports suggest that modern versions of EF6 do support this natively.
- I'll admit I'm unsure. I remember having to really fight EF6 and use workarounds like
Entity Framework Core:
- Yes. Use
HasPrincipal()
withHasForeignKey()
to define both a secondary-key onTPrincipal
and the foreign-key onTDependant
that points to that secondary-key.
- Yes. Use
As for your scenario, specifically: dbo.AspNetUsers
:
Assuming that you want to use the Email
column to uniquely identify users, then I recommend that you don't do that: Generally speaking, it's a bad idea to use mutable data (i.e. data that can change) as a key. Keys must be unique and ideally should be immutable - and while an e-mail address can be unique in some contexts (e.g. your system won't allow multiple users to share the same e-mail address) they aren't immutable (users can and do change e-mail addressees).
Another caveat: in order to use a UNIQUE CONSTRAINT
and UNIQUE INDEX
as a foreign-key target then those column(s) cannot be filtered or have NULL
s - but dbo.AspNetUser.Email
is nvarchar(256) NULL
, so you'll need to ensure all users have distinct email addresses set first.
Having said that, this will work:
-- 1. Change `Email` from `NULL` to a `NOT NULL` column, as `UNIQUE CONSTRAINT` columns cannot contain duplicates or nulls:
ALTER TABLE dbo.AspNetUsers
ALTER COLUMN [Email] nvarchar(256) NOT NULL;
-- 2. Create a UNIQUE CONSTRAINT over the `Email` column, so SQL Server knows every row has a distinct value in that column:
ALTER TABLE dbo.AspNetUsers
ADD CONSTRAINT UQ_Email UNIQUE ( Email );
-- 3. Create a new table with a FOREIGN KEY in the other table:
CREATE TABLE dbo.OtherTable (
Etc nvarchar(50) NOT NULL,
UserEmail nvarchar(256) NULL,
CONSTRAINT FK_Users_by_email FOREIGN KEY ( UserEmail ) REFERENCES dbo.AspNetUsers ( [Email] )
);
Create foreign key to a non-primary key?
Yes.
From the documentation:
Finally, we should mention that a foreign key must reference columns
that either are a primary key or form a unique constraint.
Configuring one-to-many foreign key to a non primary key property
Since you don't have any navigation property on either entity, you have to use the generic version HasOne<Roles>()
to indicate which table the foreign-key refers to. Once that is clear to EF, you don't need to pass anything to WithMany()
. Try the following -
- Declare
RoleDisplay
as an alternate-key onRoles
-
modelBuilder.Entity<Roles>(e =>
{
e.HasKey(p => p.Id);
e.HasAlternateKey(p => p.RoleDisplay);
});
- While configuring the foreign-key on
Schedule
, specify which key onRoles
it should target -
modelBuilder.Entity<Schedule>(e =>
{
e.HasKey(p => p.Id);
});
modelBuilder.Entity<Schedule>()
.HasOne<Roles>()
.WithMany()
.HasForeignKey(p => p.Role)
.HasPrincipalKey(p => p.RoleDisplay);
Hope that helps.
Rails add foreign key on non-primary key
Later this evening I seeked out some further help from the Rails IRC channel and eventually user dionysus69
pointed me to this post which was very similar to what I was looking for. For future reference this is the final solution:
class RootArea < ApplicationRecord
has_many :common_areas, foreign_key: 'root_area_id', primary_key: 'area_id'
end
class CommonArea < ApplicationRecord
belongs_to :root_area, foreign_key: 'root_area_id', primary_key: 'area_id', optional: true
end
Now I can successfully do
>> RootArea.first.common_areas << CommonArea.first
and have root_area_id
set to the proper area_id
value instead of the id
.
Related Topics
Oracle Differences Between Nvl and Coalesce
How to Create a Table from Select Query Result in SQL Server 2008
Passing Multiple Values For a Single Parameter in Reporting Services
Is There an Oracle SQL Query That Aggregates Multiple Rows into One Row
Convert Datetime Column from Utc to Local Time in Select Statement
Unknown Column in Where Clause
Why Would an in Condition Be Slower Than "=" in Sql
Grouping into Interval of 5 Minutes Within a Time Range
Multiple Insert Statements Vs. Single Insert With Multiple Values
Limit on the Where Col in (...) Condition
Case Insensitive Searching in Oracle
Split Comma Separated Column Data into Additional Columns
Cannot Delete or Update a Parent Row: a Foreign Key Constraint Fails
Cast from Varchar to Int - MySQL
SQL to Linq With Multiple Join, Count and Left Join