Print Page | Close Window

Relationship Entities are Read-only

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2009
Forum Discription: For .NET 3.5
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=939
Printed Date: 23-Jan-2026 at 6:55pm


Topic: Relationship Entities are Read-only
Posted By: sebma
Subject: Relationship Entities are Read-only
Date Posted: 17-Sep-2008 at 9:05am
Hi all,
 
I have a typical object hierarchical group structure in which a Group and have Sub-groups and so on.
I managed to mapped this recursive relationship table(RelGroups) for this database table (TrainingGroup):
 
TrainingGroup
InternalId Name
======= ====
1               Root
2               GroupA
3               GroupB
 
RelGroups
ParentId ChildId
====== =====
1             2
1             3
 
On the edmx side, it also generated the relationship mapping and I named them as ParentGroups and ChildGroups of a TrainingGroup. (I attached the edmx as well)
http://www.ideablade.com/forum/uploads/370/DataModelSkillCon_edmx.zip - uploads/370/DataModelSkillCon_edmx.zip
 
From the above I can retrieve from EntityManager the Root instance having GroupA and GroupB as children instances.
 
However, the DevForce EF generated domain model does not allow me to add/update/delete the ParentGroups or ChildGroups because they are read-only. See Create method below.
 
    public static TrainingGroup Create(EntityManager manager, string name, TrainingGroup parent)
    {
        TrainingGroup newChildGroup = manager.CreateEntity<TrainingGroup>();
        // Add custom code here
        newChildGroup.AddToManager();
        newChildGroup.Name = name;
        newChildGroup.ParentGroups.Add(parent); // ERROR! ParentGroups is read-only
        parent.ChildGroups.Add(newChildGroup);  // ERROR! ChildGroups is read-only
        return newChildGroup;
    }
 
Is there anyway to create a new TrainingGroup instance and a new relationship (ParentGroup and ChildGroup) in one transaction as above? Right now I cannot because the relationship generated is read-only.
 
 
 
 



Replies:
Posted By: GregD
Date Posted: 17-Sep-2008 at 1:59pm
Sebma:
 
The Add() method on navigation properties is the one feature of the Entity Framework not currently supported by DevForce EF. This does not constitute a problem for one-to-many navigation properties, as simply adding the child and setting its foreign key to the appropriate parent will cause it to show up in the parent's list of children. 
 
It is, however, a problem with many-to-many associations where the linking entity has no "payload"; i.e., it has no properties other than the two foreign keys.  This is the situation you have.  The reason it is a problem is that, as you know, the Entity Framework does not expose the linking entity when it has no payload. You can't add a RelGroup because no such entity exists!
 
We plan to implement support for Add() in a (soon) forthcoming release. For now your options are these:
 
Option 1. Expose the linking entity so you have something to add to. The best way to see how to do this is to go through the following process with a scratch model against a simple scratch database:
 
a. Create a linking entity with a payload column -- anything -- and generate an Entity Data Model from it.
b. Remove the payload column from the table and remove the corresponding property from the conceptual entity. 
 
The linking entity will remain exposed, with only its two foreign key columns. [1]
 
Option 2. Add a payload column *permanently* to the linking entity (and update the model).  This is the option we recommend, for a couple of reasons. First and foremost, it eliminates the somewhat painful reengineering that you'll have to undertake if you decide downstream that your linking entity really needs a payload (i.e., there's some piece of information you want to track about the association itself). We find that it is a very common occurrence for linking entities to evolve into entities that have importance in their own right and have to carry several pieces of information above and beyond the linking information itself.  Secondly, the payload can be an arbitary, single-column foreign key: something we also like. That's probably the kind of key you have for your other entities, and it's nice to have all of your entities operate the same way with respect to the primary key.
 
FYI, we'll still recommend Option 2 even after we support the Add() method. The Add() functionality won't eliminate the aggravating reengineering involved in adding a payload to a linking entity that started life without one.
 
Regards,
Greg Dunn
IdeaBlade
 
 
[1] As an aside, we recommend that you *always* make a backup of your EDMX before you do any twiddling of any sort, until you're *very* familiar with the operation you're about to perform. It's easy to get an EDMX hosed up in a way that's difficult to recover from unless you really know your way around. 
 


Posted By: sebma
Date Posted: 18-Sep-2008 at 2:31am
I used Option 2 as recommended, i.e. Added a new payload column to my linking entity (RelGroups) in database table, backed-up and removed my old edmx, re-generated the new edmx and then the domain model. Now I have access to RelGroups entity and could add new sub-group entity with the following sample codes:

    /// <summary>
    /// Use this factory method template to create new instances of this class
    /// </summary>
    /// <param name="manager">The DevForce EntityManager</param>
    /// <param name="name">The name for the new group</param>
    /// <param name="parent">The parent TrainingGroup</param>
    /// <param name="childLevel">The child node level in the group tree (This is the new "payload column" for information only), will persist to RelGroups.ChildLevel.</param>
    /// <returns></returns>
    public static TrainingGroup Create(EntityManager manager, string name, TrainingGroup parent, int childLevel)
    {

        TrainingGroup newChildGroup = manager.CreateEntity<TrainingGroup>();

        // if this object type requires a unique id and you have implemented
        // the IIdGenerator interface implement the following line
        //manager.GenerateId(aTrainingGroup, // add id column here //);

        // Add custom code here

        newChildGroup.AddToManager();
        newChildGroup.Name = name;
        RelGroup rel = RelGroup.Create(manager, parent, newChildGroup, childLevel);

        return newChildGroup;
    }

Thank-you Greg and IdeaBlade's excellent dev support!




Print Page | Close Window