Mapping two fields to the same column with the EclipseLink API - eclipselink

Hi,
I am using the EclipseLink API to create dynamic entities to represent a graph stored in database tables. The links are stored in their own table, which contains a link ID column, the start node ID and the end node ID columns, plus other user-defined columns. The nodes have their own table, where a node ID is stored plus other user-defined columns.
When doing the mapping from the links table to the nodes table I am doing this with the API:
OneToOneMapping startNodeMapping = dynamicLinkTypeBuilder.addOneToOneMapping("startNode", dynamicNodeTypeBuilder.getType(), "NODE_ID");
OneToOneMapping endNodeMapping = dynamicLinkTypeBuilder.addOneToOneMapping("endNode", dynamicNodeTypeBuilder.getType(), "NODE_ID");
When running the previous code I receive the following message in the stack trace:
Local Exception Stack: Exception [EclipseLink-48] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Multiple writable mappings exist for the field [TEST_NETWORK_LINK.NODE_ID]. Only one may be defined as writable, all others must be specified read-only.
Mapping: org.eclipse.persistence.mappings.OneToOneMapping[startNodeId]
This exception is thrown because I am mapping two fields (startNode and endNode) from the same entity to the same column/field in a different table/entity.
Do you know what could I do in order to solve this mapping problem? Would you suggest a different strategy? I cannot change the tables structure and I don't want to make one of the mappings "read only", but I am free to change the dynamic mappings.
Thank you!

The problem is as the error message states - you are using the "NODE_ID" field as a foreign key in both the startNode and endNode mappings. Essentially your object's startNode will always == the endNode when read back from the database. I believe you will want to specify different fields for the two mappings if they are meant to reference different nodes, so that they use their own foreign key. eg:
OneToOneMapping startNodeMapping = dynamicLinkTypeBuilder.addOneToOneMapping("startNode", dynamicNodeTypeBuilder.getType(), "START_NODE_ID");
OneToOneMapping endNodeMapping = dynamicLinkTypeBuilder.addOneToOneMapping("endNode", dynamicNodeTypeBuilder.getType(), "END_NODE_ID");
Both will automatically reference the primary key in the referenced table, which I assume is "NODE_ID".

Related

Is A Relational Database Design Correct For Storing This Complex Structure

TL;DR:
I want to use a non-relational design to store a tree of nodes in a self-referencing table because we will never need to relationally select subsets of data. This allows for extremely simple recursive storage and retrieval functions.
Coworker wants to use a relational design to store each specific field of the object -- I assume because he believes relational is simply always better. (he doesn't have any specific reasons) This would require more tables and more complex storage and retrieval functions, and I don't think it would serve to benefit us in any way.
Is there any specific benefits or pitfalls to either of the design methods?
How are trees normally stored in databases? Self referencing tables?
Are there any known samples of trees of data being stored in databases that might coincide with the task we are trying to solve?
At work we are using a complex structure to describe an object, unfortunately I cannot share the exact structure because of work restrictions but I will give an equivalent example of the structure and explain the features of it.
The structure can be represented in json but actually conforms to a much tighter syntax restriction.
There is four kinds of entities in the structure:
top level node
This node is a json object and it must be the top level json object
This node must contain exactly 4 attributes (meta info 1 through 4)
This node must contain exactly 1 'main' container node
container nodes
These are json objects that contain other containers and pattern nodes
Must contain exactly 1 attribute named 'container_attribute'
May contain any number of other containers and patterns
pattern nodes
These are json objects that contain exactly 3 attributes
A pattern is technically a container
May not contain anything else
attribute nodes
These are just json string objects
The top level container is always a json object that contains 4 attributes and exactly 1 container called 'main_container'
All containers must contain a single attribute called 'container_attribute'.
All patterns must contain exactly three attributes
An example of a structure in json looks like the following:
{
"top_level_node": {
"meta_info_1": "meta_info_keyword1",
"meta_info_2": "meta_info_keyword2",
"meta_info_3": "meta_info_keyword3",
"meta_info_4": "unique string of data",
"main_container": {
"container_attribute": "container_attribute_keyword",
"sub_container_1": {
"container_attribute": "container_attribute_keyword",
"pattern_1": {
"pattern_property_1": "pattern_property_1_keyword",
"pattern_property_2": "pattern_property_2_keyword",
"pattern_property_3": "unique string of data"
},
"pattern_2": {
"pattern_property_1": "pattern_property_1_keyword",
"pattern_property_2": "pattern_property_2_keyword",
"pattern_property_3": "unique string of data"
}
},
"pattern_3": {
"pattern_property_1": "pattern_property_1_keyword",
"pattern_property_2": "pattern_property_2_keyword",
"pattern_property_3": "unique string of data"
}
}
}
}
We want to store this structure in our internal office database and I am suggesting that we use three tables, one to store all json objects in a self-referencing table and one to store all json strings in a table that references the json object table, and then a third table to tie the top level containers to an object name.
The schema would look something like this:
Where an attibutes table would be used to store everything that is a json string with references to parent container id:
CREATE TABLE attributes (
id int DEFAULT nextval('attributes_id_seq'::text),
name varchar(255),
container_id int,
type int,
value_type int,
value varchar(255)
);
The containers table would be used to store all containers in a self-referencing table to create the 'tree' structure:
CREATE TABLE containers (
id int DEFAULT nextval('containers_id_seq'::text),
parent_container_id int
);
And then a single list of object names that point to the top level container id for the object:
CREATE TABLE object_names (
id int DEFAULT nextval('object_names_id_seq'::text),
name varchar(255),
container_id int
);
The nice thing about the above structure is it makes for a really simple recursive function to iterate the tree and store attributes and containers.
The downside is it's not relational whatsoever and therefore doesn't help to perform complex relational queries to retrieve sets of information.
The reason I say we should use this is because we have absolutely no reason to select pieces of these objects in a relational manner, the data on each object is only useful in the context of that object and we do not have any situations where we will need to select this data for any reason except rebuilding the object.
However my coworker is saying that we should be using a relational database design to store this, and that each of the 'keyword' attributes should have it's own table (container keyword table, 3 pattern keyword tables, 4 top level keyword tables).
The result is storing these objects in the suggested relational design becomes significantly more complex and requires many more tables.
Note that query speed/efficiency is not an issue because this object/database is for internal use for purposes that are not time-sensitive at all. Ultimately all we are doing with this is creating new 'objects' and storing them and then later querying the database to rebuild all objects.
If there is no benefit to a relational database design then is there any reason to use it over something that allows for such a simple storage/retrieval API?
Is there any significant issues with my suggested schema?
"we will never need to X" is a rather bold assumption that turns out to be unwarranted more often than you might suspect. And in fact with tree structures in particular, it is most natural for the requirement to arise to "zoom into a node" and treat that as a tree in its own right for a short time.
EDIT
And in case it wasn't clear why that matters : relational aproaches tend to offer more flexibility because such flexibility is built into the data structure. Non-relational approaches (typically implying that everything is solved in code) tend to lead to additional rounds of codeshitting once requirements start to evolve.

Batch insert return identity and object reference/sequence

With SQL Server 2K8 from C# I'm trying to do a batch insert/updates of records to a parent/child tables to optimize.
The inserts/updates will generate a key automatically which I'd like to extract via an OUTPUT, etc. and then reassign back in the domain model. For batch inserts I need to keep track of which newly generated ID belongs to which domain object in the batch list.
This example comes close to what I need, but was wondering if there's a way to not have an extra column added to the table (SequenceNumber) and still achieve the same results: http://illdata.com/blog/2010/01/13/sql-server-batch-inserts-of-parentchild-data-with-ibatis/
ie. could we rely on the order of the inserts generated from the OUTPUT into the temp table, or pass a ref GUID set on the data model and passed temporarily to the SQL just for reference purposes?
In SQL Server 2008 it is possible to use merge and output to get a mapping between the generated key and the key used in the staging table.
Have a look at this question. Using merge..output to get mapping between source.id and target.id
Unless I've misunderstood...
A surrogate key (IDENTITY or NEWID etc) isn't your actual object identifier. It's an implementation detail and has no intrinsic meaning.
You must have another identifier (name, ISBN, serial number, transaction code/date, etc) that is the real (natural) key.
Your OUTPUT clause can return the surrogate key and the natural key. You then use this to map back

Returning two-level of relational data from WCF

I'm facing very weird issue. I've 3 tables. I'm using LINQ to SQL in WCF.
Number (It has RankId foreign key which is linked to Rank table)
Rank (RankId primary key)
CategoryRank (It has also RankId foreign key which is linked to Rank table)
I'm using WCF which is returning top 10 data from Number table. When I look at n.Rank.Number (where n is the object of Number class) and n.Rank.CategoryRank at WCF side, it's showing me properly filled data. But at the client side when I check n.Rank.Number (it's showing me data filled) where as n.Rank.CategoryRank is null.
I'm returning data as List<Number>. I also tried using load options but it didn't work. At the client side HasAssignedOrLoadedValues for x.Rank.Number is true where it's false for x.Rank.CategoryRank.
I've my serialization mode to Unidirectional and also child property is true between relational tables.
Can someone guide me what's wrong with this?
Regards,
Viresh
If Number is a LINQtoSQL generated type you probably don't need to share that type with the client, instead create a custom type that is a DataContract with DataMembers and map the values you want from Number to this custom type using either reflection or something like AutoMapper. So instead you'd have the return value from the service as
List<CustomNumberType> instead.
It's obvious the n.Rank.CategoryRank is not being serialized.

ADO Entity Framework creating unwanted Entity Key

I need to use tables from a DB which I cannot alter (using linked server).
So part of my schema is a view on these table and I cannot create an FK in my DB.
When I come to creating the association in ADO.NET Entity Framework I am getting problems because a second column on the table from the external DB has an index on it and the EF is creating an Entity Key for it (it's the name descr of the record - I think they just wanted to speed the ordering on it).
When I take the Entity Key off this column in the EF entity it complains that I need it because the underlying table has a key on it.
If I leave it in I cannot map it onto anything in the table mapping of EF.
Does anyone know what I should do please?
You will have to edit the XML and remove the column from the key. Find the <EntityType> tag in the <edmx:StorageModels> section (SSDL content). Delete any <PropertyRef> in the <Key> that is not actually part of the primary key.
Once you do this, you can set "Entity Key" on the corresponding scalar property in the designer to false, and EF won't get mad. You will also not be asked to map this column in associations anymore.

Association end is not mapped in ADO entity framework

I am just starting out with ADO.net Entity Framework I have mapped two tables together and receive the following error:
Error 1 Error 11010: Association End 'OperatorAccess' is not mapped. E:\Visual Studio\projects\Brandi II\Brandi II\Hospitals.edmx 390 11 Brandi II
Not sure what it is I am doing wrong.
I believe I can add some more clarity to the issue (learning as I go):
When I look at the Mapping details and look at the association, the column for operatoraccess table (from above) is blank and the drop down only includes field from the linked table.
The Entity Framework designer is terrible - I've had the same problem many times (and your problem too, Craig):
This happens when you have a many-to-one association which is improperly setup. They could very easily fix the designer to make this process simple; but instead, we have to put up with this crap.
To fix:
Click on the association, and go to the mapping details view.
Under association, click on Maps to <tablename>. Choose the table(s) which make up the many side of the relationship (ie. the table(s) which make up the *-side of the association in the designer)
Under Column, choose the table-columns which map to each entity-side Property. You get this error when one of those entries are blank.
I had the exact same problem and this is what I did to fix it.
Make sure you have an Entity Key set in your designer on the tables your making an association with. Also check that StoreGeneratedPattern is set to Identity for that Entity Key.
There's not a lot of information in your question, but, generally speaking, this means that there is an incompletely defined association. It could be that you have tried to map one table with a foreign key to another table, but have not mapped that other table. You can also get this error when you try to do table per type inheritance without carefully following the steps for implementing that feature.
Not sure of the answer, but I've just posted a similar question, which may at least help clarify the issue you are experiencing.
Defining an Entity Framework 1:1 association
I had to go back into the database itself and clarify the foreign key relationship
I had this problem in the case where I was creating both many to 0..1 and 0..1 to 0..1 associations. One entity needed associations to multiple tables, and that entity did not have foreign keys defined for those tables.
I had to do the table mappings step that is given in the accepted answer, but note that it wasn't only for many to many associations; it applied to all the types of associations I added for this entity.
In the Mapping Details view, I had to select the entity with the non-foreign key ID columns to the various tables. This is not always the "many" side of the relationship. Only there was I able to map the related entity property to the appropriate property in the original entity. Selecting the "destination" entity would not allow me to select the properties that I needed to, and the error would still exist.
So in short, I had to map using the table related to the entity that had the "non-foreign key" ID fields corresponding to the various entities' (and their tables') primary keys that I needed to associate.
Entity A
various other properties...
Id
ContactId
OrderId
etc.
Contact entity
Id
FirstName
LastName
etc.
In the mapping details, I selected Entity A's table. It then showed both ends of the association. I mapped its Entity A's Id property to its table's actual ID column (they had different names). I then mapped the Contact entity's Id field to the ContactId field on the A entity.
Simply select the many relationship table (*) from the Association>Edit Mapping & select the appropriate relationship