Entity Framework map using Foreign Key and type field - entity-framework

This is a simplified version of the problem I'm facing. Basically, I have an existing database with code-first Entity Framework on top of, and there are several tables where I see an ObjectId and ObjectType field. Depending on the ObjectType, the table can be joined to one of several other disparate tables which do not share a hierarchy.
For example, given the following database tables:
CREATE TABLE BarCode
(
Id int NOT NULL PRIMARY KEY,
ObjectType int NOT NULL,
ObjectId int NOT NULL,
BarCodeValue varchar(20) NOT NULL,
)
CREATE TABLE Person
(
Id int NOT NULL PRIMARY KEY,
Name varchar(20),
)
CREATE TABLE Package
(
Id int NOT NULL PRIMARY KEY,
Name varchar(20),
)
I might see rows in the BarCode table with an ObjectType of 1, which correspond to Person records, or rows with an ObjectType of 2, which correspond to Package records.
In Entity Framework, how do I set up a mapping so that the Person entity can have a BarCode and the Package entity can have a Barcode? I don't see where the Map() method allows you to specify any fields other than the foreign key field. Like I said, there's really no hierarchy among these objects, it's more that they share a common attribute. Sort of like decorating a class with an interface vs. having it inherit from something.

Related

how to relate many rows to a row from the same table postgresql?

consider Amazon product category architecture (one product may have 7 parent categories another might have 2). I want to build the same thing using Postgres.
A: Is there any scaleable logical way to do this? or I must consider using a graph database.
ps: the project will not be AMAZON BIG. this is a monolith project, not a microservice.
B: my thoughts are that I should have a field named parent_categories in my category table which is an array of UUIDs of categories then a field named category_id for the products table that is related to the last category parent would work.
something like this:
CREATE TABLE categories (
id UUID PRIMARY KEY NOT NULL DEFAULT gen_random_uuid (),
name VARCHAR NOT NULL,
parent_categories UUID[]
);
CREATE TABLE products (
id UUID PRIMARY KEY NOT NULL DEFAULT gen_random_uuid (),
name VARCHAR NOT NULL,
category_id UUID[],
CONSTRAINT fk_category FOREIGN KEY(category_id) REFERENCES categories(id)
);
the problem is with joining the chained categories I'm expecting a result like the below when fetching categories (I'm using node.js) and I don't know how to join every element of that array.
categories: [{
id: "id",
name: "name",
parent_categories: [{
id: "id",
name: "name"
}]
}]
This question is about relational theory.
You have a pair of tables containing id and name, that's lovely.
Discard the array attributes, and then
CREATE TABLE product_category (
product_id UUID REFERENCES products(id),
category_id UUID REFERENCES categories(id),
PRIMARY KEY (product_id, category_id)
)
Now you are perfectly set up for 3-way JOINs.
Consider adopting the "table names are singular" convention,
rather than the current plural-form names.
Add a parent_id column to categories,
so the table supports self-joins.
Then use WITH RECURSIVE to navigate
the hierarchical tree of categories.
(Classic example in the Oracle documentation
shows how manager can be used for emp
self-joins to produce a deeply nested org chart.)

OData $metadata error

I have a WCF Data Service (5.5) sitting over an EF (5.0) model,
I'm getting the following error when I query $metadata:
"An IEdmModel instance was found that failed validation. The following errors were reported:
InvalidMultiplicityOfDependentEnd : The multiplicity of the dependent end 'QuestionsetMember' is not valid. Because the dependent properties don't represent the dependent end key, the the multiplicity of the dependent end must be '*'."
QuestionsetMember has a composite primary key of 2 columns, each of which is hooked to a primary key of another table, i.e. a foreign key exist from each column of the key to the two tables' primary keys.
I've searched but cannot find any info on "InvalidMultiplicityOfDependentEnd".
Also tried fiddling with the relationships in the EDMX, but changing the End Multiplicity causes errors which won't allow the model to compile.
Any ideas how to get round this (hopefully without changing my schema) ?
This seems to be a very rare error. I did not find anywhere else an explanation of that error. So i did find for me a solution after inspecting every single constraint and every column in both tables. To my great surprise the order of the primary key columns seems to be relevant.
For explanation: I do the database-design within the sql server management studion, and update my model with the entity framework designer.
First Table:
CREATE TABLE Table1
(
Column1 int NOT NULL,
Column2 int NOT NULL,
PRIMARY KEY (Column1,Column2)
)
Second Table:
CREATE TABLE Table2
(
Column1 int NOT NULL,
Column2 int NOT NULL,
PRIMARY KEY (Column1,Column2)
FOREIGN KEY (Column1,Column2) REFERENCES Table1(Column1,Column2)
)
This would work. But it do not work, if you would define the columns of the primary key in the second table in another order:
CREATE TABLE Table2
(
-- Changed order in definition:
Column1 int NOT NULL,
Column2 int NOT NULL,
-- Changed order in PK group:
PRIMARY KEY (Column2,Column1)
-- Leave the FK definition untouched:
FOREIGN KEY (Column1,Column2) REFERENCES Table1(Column1,Column2)
)
I think the order of the column definition has impact on the generated model. And this order could maybe have an impact in the model validation within the IEdmModel class. Who knows...

In a JPA entity hierarchy using InheritanceType.JOINED, all relationships with subclasses results in foreign key constraints on the superclass table

I have the following JPA 2.0 Entities
#Entity
#Inheritance(strategy= InheritanceType.JOINED)
public abstract class BookKeepingParent implements Serializable {
#Id
protected Long Id;
...
}
#Entity
public class Employee extends BookKeepingParent {
private String name;
#ManyToOne
private Role role;
...
}
#Entity
public class Role extends BookKeepingParent {
private String name;
...
}
I want to let JPA generate tables for me, since it makes it easier to install at multiple locations. I would usually expected it to generate this:
CREATE TABLE bookkeepingparent (
id bigint NOT NULL,
dtype character varying(31),
CONSTRAINT bookkeepingparent_pkey PRIMARY KEY (id )
)
CREATE TABLE role (
id bigint NOT NULL,
name character varying(255),
CONSTRAINT role_pkey PRIMARY KEY (id ),
CONSTRAINT fk_role_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id)
)
CREATE TABLE employee (
id bigint NOT NULL,
name character varying(255),
role_id bigint,
CONSTRAINT employee_pkey PRIMARY KEY (id ),
CONSTRAINT fk_employee_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id),
CONSTRAINT fk_employee_role_id FOREIGN KEY (role_id) REFERENCES role (id)
)
First two tables where the same, but it generated the employee table this way:
CREATE TABLE employee (
id bigint NOT NULL,
name character varying(255),
role_id bigint,
CONSTRAINT employee_pkey PRIMARY KEY (id ),
CONSTRAINT fk_employee_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id),
CONSTRAINT fk_employee_role_id FOREIGN KEY (role_id) REFERENCES bookkeepingparent (id)
)
You can notice that the fk_employee_role_id references the bookkeepingparent table, instead of the role table. I have a large heirarchy of JPA entities, and I want the bookkeepingparent to be the superclass of most of them. This is primarily because of some very specific Id generation strategies and other bookkeeping activities. This design, helps keep all this book keeping code separate from the functional code, and let programmers working on the functional code not worry about it.
All this worked alright till the the number of tables grew. Now we see that, for all ManyToOne and OneToOne relationships, JPA is generating foreign keys referring to the parent table. With 200 odd tables, the inserts are already slow because all foreign key constraints refer to the bookekeepingparent, and every entity, when persisted for the first time, inserts into the bookkeeping parent table. Which I guess is checking some 150 odd constraints.
So, following are my questions: why is JPA doing it? Is it a standard JPA behaviour? (I'm using EclipseLink) If I manually change the DB schema, are their any pitfalls to expect?
This is my first question on StackOverflow, I tried my best to search for any existing answers. Apologies if I missed any. Thanks.
You are using joined inheritance, which means that for every class, the bookkeepingparenttable is the main table and any subclass table is secondary. The primary key for the subclasses are inherited from the parent, and foreign keys must reference the id, so the will all reference the id in bookkeepingparenttable by design. Different providers allow referencing non-pk fields, but it can cause problems as resolving references can require database hits instead of using the cache.
The database constraints are not JPA related, so you can change them as required and not affect the app as long as inserts updates and deletes will still conform.

Implement 1:N relation in postgreSQL (object-relational)

I'm struggling with postgreSQL, as I don't know how to link one instance of type A to a set of instances of type B. I'll give a brief example:
Let's say we want to set up a DB containing music albums and people, each having a list of their favorite albums. We could define the types like that:
CREATE TYPE album_t AS (
Artist VARCHAR(50),
Title VARCHAR(50)
);
CREATE TYPE person_t AS (
FirstName VARCHAR(50),
LastName VARCHAR(50),
FavAlbums album_t ARRAY[5]
);
Now we want to create tables of those types:
CREATE TABLE Person of person_t WITH OIDS;
CREATE TABLE Album of album_t WITH OIDS;
Now as I want to make my DB as object-realational as it gets, I don't want to nest album "objects" in the row FavAlbums of the table Person, but I want to "point" to the entries in the table Album, so that n Person records can refer to the same Album record without duplicating it over and over.
I read the manual, but it seems that it lacks some vital examples as object-relational features aren't being used that often. I'm also familiar with the realational model, but I want to use extra tables for the relations.
Why you create a new type in postgresql to do what you need?
Why you don't use tables directly?
With n-n relation:
CREATE TABLE album (
idalbum integer primary key,
Artist VARCHAR(50),
Title VARCHAR(50)
);
CREATE TABLE person (
idperson integer primary key,
FirstName VARCHAR(50),
LastName VARCHAR(50)
);
CREATE TABLE person_album (
person_id integer,
album_id integer,
primary key (person_id, album_id),
FOREIGN KEY (person_id)
REFERENCES person (idperson),
FOREIGN KEY (album_id)
REFERENCES album (idalbum));
Or with a "pure" 1-n relation:
CREATE TABLE person (
idperson integer primary key,
FirstName VARCHAR(50),
LastName VARCHAR(50)
);
CREATE TABLE album (
idalbum integer primary key,
Artist VARCHAR(50),
Title VARCHAR(50),
person_id integer,
FOREIGN KEY (person_id)
REFERENCES person (idperson)
);
I hope that I help you.
Now as I want to make my DB as object-realational as it gets, I don't want to nest album "objects" in the row FavAlbums of the table Person, but I want to "point" to the entries in the table Album, so that n Person records can refer to the same Album record without duplicating it over and over.
Drop the array column, add an id primary key column (serial type) to each table, drop the oids (note that the manual recommends against using them). And add a FavoriteAlbum table with two columns (PersonId, AlbumId), the latter of which are a primary key. (Your relation is n-n, not 1-n.)
Sorry for answering my own question, but I just wanted to give some pieces of information I gained by toying around with that example.
ARRAY Type
I found out that the ARRAY Type in PostgreSQL is useful if you want to associate a variable number of values with one attribute, but only if you can live with duplicate entries. So that technique is not suitable for referencing "objects" by their identity.
References to Objects/Records by identity
So if you want to, as in my example, create a table of albums and want to be able to reference one album by more than one person, you should use a separate table to establish these relationships (Maybe by using the OIDs as keys).
Another crazy thing one could do is referencing albums by using an ARRAY of OIDs in the person table. But that is very awkward and really does not improve on the classic relational style.

How do I eliminate Error 3002?

Say I have the following table definitions in SQL Server 2008:
CREATE TABLE Person
(PersonId INT IDENTITY NOT NULL PRIMARY KEY,
Name VARCHAR(50) NOT NULL,
ManyMoreIrrelevantColumns VARCHAR(MAX) NOT NULL)
CREATE TABLE Model
(ModelId INT IDENTITY NOT NULL PRIMARY KEY,
ModelName VARCHAR(50) NOT NULL,
Description VARCHAR(200) NULL)
CREATE TABLE ModelScore
(ModelId INT NOT NULL REFERENCES Model (ModelId),
Score INT NOT NULL,
Definition VARCHAR(100) NULL,
PRIMARY KEY (ModelId, Score))
CREATE TABLE PersonModelScore
(PersonId INT NOT NULL REFERENCES Person (PersonId),
ModelId INT NOT NULL,
Score INT NOT NULL,
PRIMARY KEY (PersonId, ModelId),
FOREIGN KEY (ModelId, Score) REFERENCES ModelScore (ModelId, Score))
The idea here is that each Person may have only one ModelScore per Model, but each Person may have a score for any number of defined Models. As far as I can tell, this SQL should enforce these constraints naturally. The ModelScore has a particular "meaning," which is contained in the Definition. Nothing earth-shattering there.
Now, I try translating this into Entity Framework using the designer. After updating the model from the database and doing some editing, I have a Person object, a Model object, and a ModelScore object. PersonModelScore, being a join table, is not an object but rather is included as an association with some other name (let's say ModelScorePersonAssociation). The mapping details for the association are as follows:
- Association
- Maps to PersonModelScore
- ModelScore
ModelId : Int32 <=> ModelId : int
Score : Int32 <=> Score : int
- Person
PersonId : Int32 <=> PersonId : int
On the right-hand side, the ModelId and PersonId values have primary key symbols, but the Score value does not.
Upon compilation, I get:
Error 3002: Problem in Mapping Fragment starting at line 5190: Potential runtime violation of table PersonModelScore's keys (PersonModelScore.ModelId, PersonModelScore.PersonId): Columns (PersonModelScore.PersonId, PersonModelScore.ModelId) are mapped to EntitySet ModelScorePersonAssociation's properties (ModelScorePersonAssociation.Person.PersonId, ModelScorePersonAssociation.ModelScore.ModelId) on the conceptual side but they do not form the EntitySet's key properties (ModelScorePersonAssociation.ModelScore.ModelId, ModelScorePersonAssociation.ModelScore.Score, ModelScorePersonAssociation.Person.PersonId).
What have I done wrong in the designer or otherwise, and how can I fix the error?
Many thanks!
Very late to your question, I had the same issue and discovered that the entity framework designer had identified my "ScoreId" column (relative to your PersonModelScore table) as a primary key column. I changed my setting to false for my ScoreId, and all worked well afterward.
You can set single primary key in the Entity in order to avoid this error.Right Click on the Scalar Properties of the field in the Entity and disable Entity Key if there are many primary keys.
You should create a single Identity key for each table.
ModelScore should have a ModelScoreId, PersonModelScore should have a PersonModelScoreId.
References between table should be a single field.
Your PersonModelScore table should define an Id column that is identity and primary key, then
you should create a unique key on PersonId, ModelId
as for Error 3002, i had the same problem ALL my field had been marked Entity key by EF
"Go to your .edmx file, right click on the background and select 'Mapping Details'. Click on the Table you need to edit the mappings of in your .edmx window and the details should appear in your new 'Mapping Details' window. Open Properties tab (Hit F4 to bring up the 'Properties' if not open) Click on the 'Value/Property' in your 'Mapping Details' to change the Properties displayed, and from your Properties window you can now set the 'Entity Key' value to 'False'. – Chris Paton Oct 4 '14 at 18:54"
This worked for me - Thanks
This is now part of my workflow when using EF Database First. And we have a task out to update the data model.