Using the usual example for one-to-many ORM objects "Artist" and "Art", I have an Art table with a column called ArtistID that is labeled as a foreign key of "Artist" (it uses, surprise, the primary key of the Artist table). When I then have a specific Artist (called "thisArtist") and attempt to EntityDelete("thisArtist"), I get an error:
The DELETE statement conflicted with the REFERENCE constraint "FK_Art_Artists". The conflict occurred in database "ArtistTracker", table "dbo.Art", column 'ArtistID'.
I feel pretty confident that I am doing something dumb, either with my setup of relations or perhaps with my syntax. Has anyone encountered this? I don't see an example of how to EntityDelete() a specific Artist if it has foreign key constraints on entries in an Art table.
Your Artist will likely have an "arts" property, correct? And that points to an Art CFC, presumably. Your arts property probably looks like property name="arts" cfc="Art" fieldtype="one-to-many";
What's missing is to tell ORM how to handle the case where you delete the Artist. In your case, you need to add a "cascade" attribute onto the arts property, like so: property... cascade="all-delete-orphan";
Then, when you entityDelete the Artist, Hibernate will also delete any orphaned Art elements that belonged to that artist.
When creating one-to-many relationships, you almost always want to specify cascade="one-to-many" and inverse="true".
Related
This may be too much of an opinion-based question but here goes:
I've found an interesting quirk with Entity Framework and database migrations. It seems that whenever we create a foreign key it also creates an index on that column.
I read this SO question: Entity Framework Code First Foreign Key adding Index as well and everyone seems to say it's a great, efficient idea but I don't see how; indexing a column is very circumstance-specific. For instance, EF is indexing FKs on my table that are almost never (~1%) used for searches and are also on a source table, meaning that even when I join other tables, I'm searching the FK's linked table using it's PK...there's no benefit from having the FK indexed in that scenario (that I'm aware of).
My question:
Am I missing something? Is there some reason why I would want to index a FK column that is never searched and is always on the source table in any joins?
My plan is to remove some of these questionable indexes but I wanted to to confirm that there's not some optimization concept that I'm missing.
In EF Code First, the general reason why you would model a foreign key relationship is for navigability between entities. Consider a simple scenario of Country and City, with eager loading defined for the following LINQ statement:
var someQuery =
db.Countries
.Include(co => co.City)
.Where(co => co.Name == "Japan")
.Select(...);
This would result in a query along the lines of:
SELECT *
FROM Country co
INNER JOIN City ci
ON ci.CountryId = co.ID
WHERE co.Name = 'Japan';
Without an Index on the foreign key on City.CountryId, SQL will need to scan the Cities table in order to filter the cities for the Country during a JOIN.
The FK index will also have performance benefits if rows are deleted from the parent Country table, as referential integrity will need to detect the presence of any linked City rows (whether the FK has ON CASCADE DELETE defined or not).
TL;DR
Indexes on Foreign Keys are recommended, even if you don't filter directly on the foreign key, it will still be needed in Joins. The exceptions to this seem to be quite contrived:
If the selectivity of the foreign key is very low, e.g. in the above scenario, if 50% of ALL cities in the countries table were in Japan, then the Index would not be useful.
If you don't actually ever navigate across the relationship.
If you never delete rows from the parent table (or attempt update on the PK) .
One additional optimization consideration is whether to use the foreign key in the Clustered Index of the child table (i.e. cluster Cities by Country). This is often beneficial in parent : child table relationships where it is common place to retrieve all child rows for the parent simultaneously.
Short answer. No.
To expand slightly, at the database create time, entity framework does not know how many records each table or entity will have, nor does it know how the entities will be queried.
*In my opinion * the creation of a foreign key is more likely to be right than wrong, I had massive performance issues using a different ORM which took longer to diagnose because I thought I had read in the documentation that it behaved the same way.
You can check the Sql statement that EF produces and run it manually if you want to double check.
You know your data better than EF does, and it should work just fine if you drop the index manually.
IIRC you can create 1 way navigation properties if you use the right naming convention, although this was some time ago, and I never checked whether the index was created.
Change the conflict FK (Foreign Key) name in ApplicationDbContextModelSnapshot file with another one. Then add migration again. It will override to it and not gonna give error.
Lets say you have two entity named Parent and Child.
Child entity is DEPENDENT of Parent entity.
A weak key of child entity is the NAMEOFCHILD.
Is it possible for the Parent entity to have NAMEOFCHILD as a foreign key?
This idea has not been talked about in class. I was wondering is this possible in SQL?
If so, should i just add
FOREIGN KEY (NAMEOFCHILD) source CHILD
in my table?
In the database schema, yes (if Child.NAMEOFCHILD has a unique index). In entity framework, no. EF doesn't support associations to unique indexes (yet). But this is just on the technical level. Whether it's meaningful is another question.
Also, beware of painting yourself in a corner. When both foreign keys are not nullable you'd never be able to insert data, because you can't insert two records at a time and sequential inserts always cause foreign key violations. You would be able to design the database schema but never get any data in.
I've got two entities, one called Site and the other called Assignment. A Site may or may not have an associated Assignment. An Assignment is only ever associated with one Site. In terms of C#, Site has a property of type Assignment which could hold a null reference.
I have got two tables by the same names in the database. The Assignment table's PK is also its FK back to the Site table (rather than Site having a nullable FK pointing to Assignment). The SQL (with fields omitted for brevity) is as follows
CREATE TABLE Site(
SiteId INT NOT NULL CONSTRAINT PK_Site PRIMARY KEY)
CREATE TABLE Assignment(
AssignmentId INT NOT NULL CONSTRAINT PK_Assignment PRIMARY KEY,
CONSTRAINT FK_Assignment_Site FOREIGN KEY (AssignmentId) REFERENCES Site (SiteId))
I'm using Fluent NHibernate's auto persistence model, which I think I will have to add an override to in order to get this to work. My question is, how do I map this relationship? Is my schema even correct for this scenario? I can change the schema if needs be.
You need to read these:
http://ayende.com/Blog/archive/2009/04/19/nhibernate-mapping-ltone-to-onegt.aspx
http://gnschenker.blogspot.com/2007/06/one-to-one-mapping-and-lazy-loading.html
https://www.hibernate.org/162.html
it's not possible to have one-to-ones lazy loaded unless they are not-nullable, or you map them as a many-to-one with one item in it
I am using NHibernate with a SQL CE desktop database, and I'm getting an odd error when I try to do an update. SQL CE is throwing Error 25026: "A foreign key value cannot be inserted because a corresponding primary key value does not exist."
The exception occurs when performing a cascading update of a collection property of an entity object. The entity object is an Owner, and the collection property is Projects (IList), the projects for a particular Owner. In my database, the primary key of the Owners table is a three-character string (the owner's initials), with a corresponding foreign key in the Projects table.
Here's why I am puzzled: NHibernate can fetch all of the records for a particular owner (for example, "DCV"). And in my code, I can add a new Project object to Owner.Projects with no problem. I take the owner ID value directly from the Owner object fetched from the database, so I know the primary key exists in the Owners table. But when I do an ISession.SaveOrUpdate() on my Owner object, I get the foreign key error described above.
Am I dealing with some idiosyncracy of NHibernate, or some mundane error in my code or mappings? Any thoughts that would help me troubleshoot this problem greatly appreciated!
David Veeneman
Foresight Systems
I found the answer. It has to do with how NHibernate handles one-to-many associations. From the NHibernate Documentation, Sec. 6.4, One-To-Many Associations:
Very Important Note: If the
column of a association
is declared NOT NULL, NHibernate may
cause constraint violations when it
creates or updates the association. To
prevent this problem, you must use a
bidirectional association with the
many valued end (the set or bag)
marked as inverse="true". See the
discussion of bidirectional
associations later in this chapter.
If you are having this problem, remove the foreign key constraint temporarily and run your code, outputting NHibernate's SQL to the console. You will see that NHibernate first inserts the new record without the foreign key, then calls up the record, then inserts the foreign key into the record. The first operation is what generates the foreign key error.
The solution, as the NHibernate documentation points out, is to make the relation bidirectional.
I'm trying to model artists and songs and I have a problem where I have a Song_Performance can be performed by many artists (say a duet) so I have an Artist_Group to represent who the songs is performed by.
Well, I now have a many-to-many relationship between Artist and Artist_Group, where an Artist_Group is uniquely identified by the collection of artists in that group. I can create an intersection entity that represents an Artist's participation in an Artist_Group (Artist_Group_Participation?)
I'm having trouble coming up with how to come up with a primary key for the Artist_Group entity that preserves the fact that the same set of artists represents the same group, and lacking a primary key for the Artist_Group entity means I'm lacking a foreign key for the Artist_Group_Participation entity.
The book "Mastering Data Modeling" by John Carlis and Joseph Maguire mention this shape and refer it to as a "Many-Many Collection Entity" and state that it is very rare, but doesn't state how to resolve it since obviously a many-to-many relationship can't be stored directly in a RDBMS. How do I go about representing this?
Edit:
Looks like everyone is suggesting an intersection table, but that's not my issue here. I have that. My issue is enforcing the constraint that you cannot add an Artist_Group entry where the group of artists that it contains are the same as an existing group, ignoring order. I thought about having the ID for Artist_Group be a varchar that is the concatenation of the various artists that comprise it, which would solve the issue if order mattered, but having an Artist_Group for "Elton John and Billy Joel" doesn't prevent the addition of a group for "Billy Joel and Elton John".
I guess I'm missing the point of the "Artist_Group" relation.
The data model in my mind is:
Artist: an individual person.
Song: The song itself.
Performance: A particular performance or arrangement of a song. Usually this would have one song, but you could provide an m:n linking table to accommodate a medley. Ideally, this would be a single real performance, i.e., there would be an associated date.
Recording: A particular fixed version of a performance (CD or whatever). Usually a Performance only has one Recording, but having a separate table would handle the Grateful Dead / multiple-bootleg scenario, as well as re-release albums, radio play vs. live vs. CD versions, etc.
Performance_Artists: A linking table from a particular performance to a list of performers. For each, you could also have an attribute that describes their role(s) in the performance (vocalist, drummer, etc.).
There's no explicit relationship between a set of performers, except that they share performances in common. Thus, any table that attempts to combine random sets of artists outside the context of a recording is not an accurate relational model, as there is no real relationship.
If you are trying to represent an explicit relationship between a set of artists (i.e., they are in the same band), well, bands have names that have uniqueness (though not enough to be a primary key), and a band could be stored simply as an Artist, and then have an Artist_Member linking table that is self-referencing back to the individual Artist records. Or you could have a separate Band table, and a Band_Members table to assign artists to it, perhaps with dates of membership. Either way, just remember that band members change over time and band roles change from one song to the next, so associating a band with a performance should not substitute for linking performances directly to the artists involved.
The primary key for both the Artist and Artist_Group would be an numeric, incremental ID. Then you'd have an Artist_Group_Participation table that has two columns: artist_id and group_id. These would be foreign keys that refer to the ID of their respective tables. Then to SELECT everything you'd use a JOIN.
EDIT: Sorry, I misunderstood your question. The only other way I can think of is add an "artists" column to your Artist_Group table that contains a serialized array (assuming you're using PHP, but other languages have equivalents) of the artists and their IDs. Then just add a UNIQUE constraint to the column.
You could make each artist's ID correspond to a bit in a bitfield. So if Elton John is ID 12 and Billy Joel is ID 123, then the "group" formed by a duet between Elton John and Billy Joel is Artist_Group ID 10633823966279326983230456482242760704 (i.e. it has the 12th and 123rd bit set).
You could enforce the relationship using the intersection table. For example, using a CHECK constraint in PostgreSQL:
CREATE TABLE Artist_Group_Participation (
artist_id int not null,
artist_group_id int not null,
PRIMARY KEY (artist_id, artist_group_id),
FOREIGN KEY (artist_id) REFERENCES Artists (artist_id),
FOREIGN KEY (artist_group_id) REFERENCES Artist_Group (artist_group_id),
CHECK (B'1'<<artist_id & artist_group_id <> 0)
);
Admittedly, this is a hack. It applies extra significance to the Artist_Group surrogate key, when surrogate keys are supposed to be unique but not contain information.
Also if you have thousands of artists, and new artists every day, things could get unwieldy because the length of the Artist_Group key's data type needs to grow larger all the time.
I guess you could build a primary key by sorting and concatenate the artist ids ??
group: 3,2,6 -> 2-3-6 and 6,3,2 -> 2-3-6
I don't have much experience in RDBMS. However, I have read papers of Codd and books by C.J. Date.
So, instead of using RDBMS jargon, I'll try to explain in more common sensical terms (at least to me!)
Here goes -
Singer names should be standard on "First Name - Last Name" basis
Each "Singer" should have an entry in the "Artists Group" table even if they have performed solo
Each entry in the "Artists Group" will consist of multiple "Singer" ordered alphabetically. There should be a single occurance of a specific combination.
Each song will have an entry of a unique record from "Artists Group" regardless of whether they are solo, duets or in a gang.
I don't know if this makes much sense, but it's my two cents!