Linq to SQL parent-child relation direction - c#

I have a parent-child relation among two tables named: Relation and Resource, so that Relation.RESOURCE_ID == Resource.ID
If I write my association into the dbml file, so that Relation --> Resource on RESOURCE_ID = ID then I am unable to add a Resource to a Relation entity. The cardinality of association is one to one.
tbl_res_Resource resoure = new tbl_res_Resource()
{
//ID is auto calculated
RESOURCE_KEY = "some key",
RESOURCE_TYPE = 20,
};
tbl_res_Relation relation = new tbl_res_Relation()
{
ENTITY_ID = 10,
ENTITY_TYPE_ID = 10,
//ID is auto calculated
//RESOURCE_ID should be inferred
};
relation.Resource = resoure;
context.tbl_res_Relations.InsertOnSubmit(relation);
context.SubmitChanges();
Submit changes will throw
System.Data.Linq.ForeignKeyReferenceAlreadyHasValueExceptio with the message 'Invalid operation due to the current state of the object'.
But if I go to the model (dbml) and reverse the association ( so Resource --> Relation on ID == RESOURCE_ID) then everything work fine.. without changing a line of code.
Keep in mind that all the association are defined only at dbml level, there is no foreign key into database.
What I am missing here?

What I am missing here?
Nothing, that is correct. It doesn't matter that the cardinality is one-to-one. An association in LINQ2SQL is an abstraction in the application layer that is the equivalent of defining a foreign key in the database layer. And LINQ2SQL expects you to follow the constraints of that association just the same as you would have to follow the constraints of an equivalent foreign key in the database layer.
what i don't understand is why reversing the 1-1 association (in teh dbml model) will break the association. It's a one to one, it does not have a preferred direction nor constraints at DB level.
Again this has nothing to do with cardinality (one-to-one) and associations always have a direction (parent to child(ren)) depending on how you set them up. If you look in the Properties window of the association, you'll see it says which object is the Parent and which is the Child.
In your code you're setting the relation.Resource field to a resource object, ergo saying that the resource is the parent and relation is the child:
relation.Resource = resoure;
The above is the equivalent of in the database layer making relation the child table with a foreign key defined on the Resource field relating back to the parent resource table.
If your association is defined such that relation is the parent, then your above code fails to the constraint because you have a resource child object that you're not assigning a parent to. You would need something like the following to adhere to the constraint:
resource.Relation = relation;

Related

Microsoft Entity Framework Core: Cannot insert duplicate key in object

I am trying to update a parent entity, GuildMemberTeam, with child entities, GuildMember, Team and GuildMemberChallenge which also has a child entities, GuildMember and Challenge but am getting the following inner exception:
Inner Exception 1: SqlException: Violation of PRIMARY KEY constraint
'PK_Challenge'. Cannot insert duplicate key in object 'dbo.Challenge'.
The duplicate key value is (15ae8798-8567-457b-812a-5820cf7843e5). The
statement has been terminated.
The only new entity is the GuildMemberTeam as all the others already exist, but these are checked and recreated as follows:
public void AddChallenge(Challenge challenge)
{
if (challenge != null)
{
var id = challenge.Id == default(Guid) ? Guid.NewGuid() : challenge.Id;
Challenge = new Challenge(id, challenge.Name, challenge.Phase, challenge.Type, challenge.Star, challenge.Gear, challenge.Level, challenge.Reward);
}
}
This works for all the other entities apart from Challenge where i get the error. Can anyone please help me understand what i am doing wrong.
It doesn't change the fact that the problem is that you are trying to insert the same row twice (same Guid=Id) into the dbo.Challenge table.
This might be due to a debugging issue or something. You can either delete the row from the table with a
DELETE FROM [Challenge] WHERE Id = '15ae8798-8567-457b-812a-5820cf7843e5' and try running the app again.
If this doesn't solve your problem your entity management is faulty and you have to revise the ID handling. Implement ID checking before you try to save your context or something like that.
The other issue might be that your classes are not defined properly and EF doesn't recognize the relations. The relationships you are talking about are not parent-child, they are either one-to-many, many-to-many, many-to-one or none. DB RELATIONS
Each of your POCO-s should contain and instance of the other class, thus you define a relationship. E.g. if your GuildMemberChallenge contains an IEnumerable and a property with type of challenge.
If none of the above are a solution I need some more code (your classes, the repository) to figure it out.
Update:
When you are adding a new GuildMemberChallenge, which I assume you are trying to do now. You should set it's Challenge property to an existing entity if it exists, if it doesn't you can create one, but at the moment you are trying to create a Challenge that already exists in the database.
You are creating new Challenge but pass id of existing Challenge if it is set.
var id = challenge.Id == default(Guid) ? Guid.NewGuid() : challenge.Id;
I think you, that if you create new entity you should always create new Id
var id = Guid.NewGuid();

One-to-one self-relationship and Entity Framework

I would like to have entity which can have a child (one or zero). This child is same type as parent. I am not sure how to set entity framework becouse I would like to have two navigation properties for every entity. One for navigation to child and one for navigation to parent. Basically it is exactly the same structure as doubly linked list.
I think this table structure should be enough:
int | id | PK
int | id_next | FK
text | data
But how can I create navigation properties for next/prev items? I am able to create only navigation property for next item.
Thanks for help.
You can't. The problem here is that a one-to-one relation has a very specific requirement - FK value must be unique in the whole table. Once the uniqueness is not enforced you can add a second entity pointing to the same parent and you have a one-to-many relation.
To enforce this in a self referencing relation like you described in your example you will place an unique index on the id_next and it will work in SQL server. The problem is that entity framework doesn't support unique keys. Because of that entity framework is only able to build one-to-one relations between two different entity types where FK in the dependent the entity type is also its PK (the only way how to force FK to be unique) = both entities has same PK value. This cannot work with a self referencing relation because you cannot have two same PK values in one table.
You can do this in EF4 by specifying a 0..1 -> 0..1 relationship on the entity. Name one of the navigation properties "Previous" and the other "Next". This will create a hidden field on the underlying DB.
I haven't thoroughly tested this approach but it seemed to work when I created the database script.
Research Tree structures in the Entity Framework. You basically want a vertical tree (i.e. one branch). The framework won't enforce only one branch, but you can manage that in your business logic.

remove foreign key property cause an exception

I don't want to use foreign key association to CompanyType (member that will hold the foreign key id) but prefer to use navigation property. So I removed the CompanyTypeId.
I get this exception that relates the relationship between entity Company and CompanyType:
Error 5: The element 'Principal' in
namespace
'http://schemas.microsoft.com/ado/2008/09/edm'
has incomplete content. List of
possible elements expected:
'PropertyRef' in namespace
'http://schemas.microsoft.com/ado/2008/09/edm'.
How can I remove those id's from the POCOs without getting the exception?
This is the difference between Foreign key association and Independent association. Both associations use navigation properties but only Foreign key association uses FK property as well. You can either remove them globally as #Robbie mentioned or you can change the type manually for selected relation.
Select the relation in entity framework designer
In properties remove Referential constraints
Go to Mapping window and map the relation
Here is the screen shot from one of my testing application with one-to-many relation between Order and OrderLine entities:
As you can see there is no OrderId in the OrderLine entity and referential constraints of the relation are empty. Also mapping of the relation is specified.
BUT you can't never remove Id from CompanyType. Ids (PKs) are mandatory. You can only change its accessibility in its properties.
When you imported in your Model from your DB you are asked if you want to:
"Include Foreign key columns in the model"
you need to switch this off.

Self-Referencing FK Generating Strangly

In the screenshot below is an Entity (URL) in my model. The ParentId field is a self-referencing FK (points to Url.Id). You can see this navigation at the bottom of the screenshot.
In my SQL and my DB, which I generate the EDMX from, the self-referencing FK is called FK_Urls_Parent:
-- Creating foreign key on [ParentId] in table 'Urls'
ALTER TABLE [Urls]
ADD CONSTRAINT [FK_Urls_Parent]
FOREIGN KEY ([ParentId])
REFERENCES [Urls]
([Id])
ON DELETE NO ACTION ON UPDATE NO ACTION;
My questions are:
Why did EF generate Urls1 and Url1 just from that one FK? Url1 is a 0 or 1 property that is 'FromRole' Urls1. Urls1 is 'FromRole' Urls 'ToRole' Urls1. It seems like EF is making a navigation property that is the exact same as Url table. Why would it do this and can I do something to make it just generate the one, desired Navigation property: Urls1?
Okay, so not quite as important, but can I control the name of the Navigation property based on the FK name or something in the DB? I hate that it names it 'Url1'. I would prefer 'Parent', but don't want to have to manually change it in the designer every time I regenerate the model.
Thanks.
It is modeling both sides of the relationship. In other words, one of the properties will be the entry being pointed to by this entry's ParentId. The other will be the entry(s) whose ParentId field points to this entry. You can disable one side in the relationship properties, or rename them to make sense. Such as, for instance, ParentUrl and ChildUrls.
I'm not 100% certain how to get to the property relation dialog without opening the program myself, which I can't right now. I do know for me it appears in the (by default) bottom-right properties window when the link is selected.
As far as making this change somehow permanent across model regenerations, I know of no way to do this. Hopefully someone else will know, because it would save me a lot of time too!

LINQ to SQL - Problem with 1-to-1 association

In the L2S designer I have dropped a table and a view. I tried adding an association between the 2 on their primary keys. This should be a one-to-one relationship, so I set the cardinality property of the association as such.
But, when coding I can't access the child property.
Any suggestions?
EditI just created a view in sql server that has the fields I want, and dropped that into L2S. Much simpler.
In my experience Linq To SQL requires the Primary/Foreign key relationships established in the DB. Otherwise, you'll have to do a join.
Not sure if this applies to your situation, but it may...
Linq To SQL Without Explicit Foreign Key Relationships
UPDATE:
It appears that you can get what you're looking for without establishing the Primary/Foreign key relationships in the database. In the LinqToSQL designer set primary keys on both columns on each table. I also had to turn off Auto-Sync on Parent Table's column that I assigned as a primary key.
Auto-Sync is described here..
Instructs the common language runtime (CLR) to retrieve the value after an insert or update operation.
Link:
http://msdn.microsoft.com/en-us/library/bb386971.aspx
We had this problem with views.
We simply defined the keys in the DBML editor and the property was finally defined.
Did you disable (set to false) either the child or parent property?
Did you perhaps mapped the one-to-one relationship the wrong way around (like I did less than an hour ago)?

Categories