What is Android Room foreign key used for? - sqlite

What exactly is Room #ForeignKey used for?
I know that it is used for linking two tables, so that whenever some update happens to the parent it updates children as well. For example,
onDelete = ForeignKey.CASCADE
I suppose it's nothing but my given definition (second paragraph), right?.
The reason I am asking this question is in OrmLite for example when you define foreign = true then you can have join database and can fill the foreign value with data. This you can not do with #ForeignKey of Room.
Here is a detailed explanation of what foreign does in OrmLite.
Am I right?

FKs (foreign keys) are a relational database concept. A FK says table subrows appear elsewhere uniquely. Equivalently, a FK says entities that participate in a relation(ship)/association participate uniquely in another. Those statement are equivalent because in a relational database a table represents entities/values that participate together per a relation(ship)/association--hence "the Relational Model" & "the Entity-Relationship Model".
The FK graph can be used for convenience/shorthand: default join conditions; preventing updates to invalid states; cascading updates; getting a unique value associated with an entity in the other relation(ship)/association; simultaneously setting values in one relation(ship)/association and the other one. FKs are wrongly called "relationships" and don't have to be known to query. They must be known to ask for a single value associated with an entity, but we can always just ask for a set of values whether or not it might always only ever have one element.
FKs, CKs (candidate keys), PKs (primary keys) & superkeys (unique column/field sets) are special cases of constraints, which are just conditions that are always true in every database state & (equivalently) businesss situation. They are determined by the relation(ship)s/associations & the valid business situations that can arise. When we tell the DBMS about them it can prevent update to a state that must be invalid because it violates them.
What is the difference between an entity relationship model and a relational model?

Related

Using a GUID as entity Id vs the entity's "actual" Id

In every cosmos db repository example I've seen, the id/row key has been generated like this: {partitionKey}:{Guid.newGuid()}. I'm working on a web api where the user won't necessarily have any way of knowing what this random GUID is. But they will know the EmployeeId, ProjectId etc. of the respective object, so I'm wondering if there are any issues with using i.e. EmployeeId as both the partition key and Id?
There's nothing technically wrong with the approach of setting id and partition key the same however you will have just one document per partition and that's bad design IMHO as all your read queries will be cross-partition queries (e.g. listing all employees).
One approach could be to set the partition key as the type of the entity (Employee, Project etc.) and then set the id as the unique identifier of the entity (employee id, project id etc.).
To be honest, if you know the partition key AND the item id, you can do a Point read which is the fastest.
We used to also take the approach of using random guids for all item IDs, but this means you will always need to know this id and partition key. Sometimes a more functional key as the item ID makes more sense so have a good thought about it!
And remember, an item ID is not unique, the uniqueness is only within the partition key.
So you could have two items with the same item ID and different partition key.

How do I define a dimension so that null values in the FK are not ignored when showing all values?

I a modeling an OLAP cube using Modrian Workbench Schema and using Jaspersoft to present it. The cube is built upon a fact table with FKs to dimension tables.
Currently my fact table has nullable foreign keys to the dimensions, which I personally find interesting (and, as far as I know, it is just s styling decision whether to use nullable or not nullable FKs ( https://dba.stackexchange.com/questions/3512/fact-table-foreign-keys-null ).
The problem is that when selecting ALL States (State is a dimension in my design), I get only the records that have a state, not the records without states (in which the state id is null).
Is Mondrian capable of getting the rows that have not state id information? How can I define that?
I think you'll have to go with non-nullable FKs and a none / n/a / unknown etc. member if you want the ALL member to refer to all facts.
If you later want to write queries that only consider rows with real dimension values, you can exclude the none member again.

EF4: Filtering out referenced entities that do not exist

I have an Entity Framework 4 design that allows referenced tables to be deleted (no cascade delete) without modifying the entities pointing to them. So for example entity A has a foreign key reference to entity B in the ID field. B can be deleted (and there are no FK constraints in the database to stop that), so if I look at A.B.ID it is always a valid field (since all this does is return the ID field in A) even if there is no record B with that ID due to a previous deletion. This is by design, I don't want cascading deletes, I need the A records to stick around for a while for auditing purposes.
The problem is that filtering out the non-existing deleted records is not as easy as it sounds. So for example if I do this:
from c in A
select A.B.somefield;
This results in a OUTER JOIN in the generated SQL so it's picking up all the A records even if they refer to missing B records. So, the hack I've been using to solve this (since I can't figure out a better way!) is do add a where clause to check a string field in the referenced B records. If that field in the B entity is null, then I assume B doesn't exist.
from c in A
where c.B.somestringfield != null
select A.B.somefield;
seems to work IF B.somestringfield is a string. If it is an integer, this doesn't work!
This is all such a hack to me. I've thought of a few solutions but they are just not practical:
Query all tables that reference B when a B is deleted and null out their foreign keys. This is so ugly, I don't want to have to remember to do this if I add another entity that references B in the future. Not to mention a huge performace delay resolving all the references whenever I delete something.
Add a string field to every table that I can count on being there that I can check to see if the entity exists. Blech, I don't want to add a database field just for this.
Implement a soft delete and keep all the referencial integrity intact - essentially set up cascading deletes, but this is going to result is huge database bloat since I can't clean up a massive amount of records due to the references. No go.
I thought I had this problem licked with the "check if a field in the referenced entity is null" trick but it breaks under conditions that I don't completely understand (what if I don't have any strings in the referenced table? What kinds of fields will work? Integers won't.)
As an example if I have an integer field "count" in entity B and I check to see if it's null like:
from c in A
where c.B.count != null
select c.B.count;
I get a bunch of records with null for count mixed in with the results, and in fact the query bombs out with an "InvalidOperationException: The cast to value type 'Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type."
So I need to do
from c in A
where c.B.count != null
select new { count = (int?)c.B.count };
to even see the null records. So this is pretty baffling to me how that query can result in null records in the results at all.
I just discovered something, if I do an explicit join like this, the SQL is INNER JOIN and everything works great:
from c in A
join j in B on A.B.ID equals j.ID
select c;
But this sucks. I'll have to modify a ton of queries to add explicit join clauses instead of enjoying the convenience of the relationship fields I get with the EF. Kinda defeats the purpose and adds a buch more code to maintain.
When you say that your first code snippet creates an OUTER JOIN then it's the case because B is an optional navigation property of entity A. For a required navigation property EF would create an INNER JOIN (explained in more detail here: https://stackoverflow.com/a/7640489/270591).
So, the only alternative I see to your last code snippet (using explicit join in LINQ) - aside from using direct SQL - is to make your navigation property required.
This is still a very ugly hack in my opinion which might have unexpected behaviour in other situations. If a navigation property is required or optional EF adds a "semantic meaning" to this relationship which is: If there is a foreign key != NULL there must be a related entity and EF expects that you don't have removed the enforcement of the FK constraint in the database.

insert data from a asp.net form to a sql database with foreign key constraints

i have two tables
asset employee
assetid-pk empid-pk
empid-fk
now, i have a form to populate the asset table but it cant because of the foreign key constraint..
what to do?
thx
Tk
Foreign keys are created for a good reason - to prevent orphan rows at a minimum. Create the corresponding parent and then use the appropriate value as the foreign key value on the child table.
You should think about this update as a series of SQL statements, not just one statement. You'll process the statements in order of dependency, see example.
Asset
PK AssetID
AssetName
FK EmployeeID
etc...
Employee
PK EmployeeID
EmployeeName
etc...
If you want to "add" a new asset, you'll first need to know which employee it will be assigned to. If it will be assigned to a new employee, you'll need to add them first.
Here is an example of adding a asset named 'BOOK' for a new employee named 'Zach'.
DECLARE #EmployeeFK AS INT;
INSERT (EmployeeName) VALUES ('Zach') INTO EMPLOYEE;
SELECT #EmployeeFK = ##IDENTITY;
INSERT (AssetName, EmployeeID) VALUES ('BOOK',#EmployeeFK) INTO ASSET;
The important thing to notice above, is that we grab the new identity (aka: EmployeeID) assigned to 'Zach', so we can use it when we add the new asset.
If I understand you correctly, are you trying to build the data graph locally before persisting to the data? That is, create the parent and child records within the application and persist it all at once?
There are a couple approaches to this. One approach people take is to use GUIDs as the unique identifiers for the data. That way you don't need to get the next ID from the database, you can just create the graph locally and persist the whole thing. There's been a debate on this approach between software and database for a long time, because while it makes a lot of sense in many ways (hit the database less often, maintain relationships before persisting, uniquely identify data across systems) it turns out to be a significant resource hit on the database.
Another approach is to use an ORM that will handle the persistence mapping for you. Something like NHibernate, for example. You would create your parent object and the child objects would just be properties on that. They wouldn't have any concept of foreign keys and IDs and such, they'd just be objects in code related by being set as properties on each other (such as a "blog post" object with a generic collection of "comment" objects, etc.). This graph would be handed off to the ORM which would use its knowledge of the mapping between the objects and the persistence to send it off to the database in the correct order, perhaps giving back the same object but with ID numbers populated.
Or is this not what you're asking? It's a little unclear, to be honest.

Should I use a composite key for a map table, which is also used for a foreign key?

I am using ASP.NET and the Entity Framework to make a website. I currently have a map table for a many to many relationship between... let's say users and soccer teams. So:
Users
Teams
UserTeams
Part 1: Is it best practice to use a composite key for the primary key of the map table? In other words:
UserTeams table
PK UserId
PK TeamId
PreferenceId
Part 2: The caveat is that I also have another table. Let's call it "UserTeamPredictions" that stores the user's predictions for a given team for each year. That table has a foreign key that points back to the map table. So it looks something like this:
UserTeamPredictions table
PK UserTeamPredictionId
FK UserId
FK TeamId
Prediction
PredictionYear
This seems to work fine in the Entity Framework, however, I have had some problems when referencing relationships in third-party controls that I use like Telerik. Even though it might not be the ideal data setup, should I change the table structure/relationships so that its easier to work with in the code with data binding and other things?
The change would be to add an integer primary key to the UserTeams map table, allowing the UserTeamPredictions table to reference the key directly, instead of through the composite key as it currently does:
UserTeams table
PK UserTeamId
FK UserId
FK TeamId
PreferenceId
UserTeamPredictions table
PK UserTeamPredictionId
FK UserTeamId
Prediction
PredictionYear
What do you think!?
You should change it. Search stack overflow for discussions on "natural keys" - it's almost universally agreed that surrogate keys are better, especially when using entity generation. Natural or composite keys do not play well with entity framework style DAL layers in general. For example, Lightspeed and Subsonic both require that you have a single unique column as a PK... Lightspeed in it's current version even goes so far to insist that your column is called "Id", although that will be changing next version.
I would choose not to. I would use a surrogate key and put a unique index on the UserId and TeamId columns. I get really sick of composite keys when there are more than two, and rather than have a mix of composite and surrogate keys, I choose to go with all surrogate, meaningless autoincrement keys wherever possible.
This has the bonus of giving you good performance on joins, and means you always know the key for a given table (table name + ID), without having to reference the schema. Some ORM tools only work properly with single column rather than composite keys, too.

Resources