views:

54

answers:

1

I have the following poco class:

public class Category : IDisplayName
{
    private ICollection<Category> children;
    private Category parent;

    public Category()
    {
        children = new List<Category>();
    }

    public int Id { get; set; }

    public string Name { get; set; }

    public virtual Category Parent
    {
        get { return parent; }
        set
        {
            parent = value;

            // if (value != null && parent.Children.Contains(this) == false)
            // {
            //      parent.Children.Add(this);
            // }
        }
    }

    public virtual ICollection<Category> Children
    {
        get { return children; }
        set { children = value; }
    }
}

This is the Mapping file (I am not sure if this is correct.. but I am out of ideas and there is bugger all documentation out there...)

public class CategoryEntityConfiguration : EntityConfiguration<Category>
{
    public CategoryEntityConfiguration()
    {
        Property(x => x.Name).IsRequired();

        HasMany(x => x.Children).WithOptional(x => x.Parent);
        HasOptional(x => x.Parent).WithMany(x => x.Children);
    }
}

Notice the "Parent" property and how I am not adding them each using the "Children" collection.

var cat_0 = new Category { Name = "Root" };            
var cat_1 = new Category { Name = "Property", Parent = cat_0 };
var cat_2 = new Category { Name = "Property Services", Parent = cat_1 };
var cat_3 = new Category { Name = "Housing Association", Parent = cat_2 };
var cat_4 = new Category { Name = "Mortgages & Conveyancing", Parent = cat_2 };
var cat_5 = new Category { Name = "Property Management", Parent = cat_2 };
var cat_6 = new Category { Name = "Property Auctions", Parent = cat_2 };
var cat_7 = new Category { Name = "Landlords Wanted", Parent = cat_2 };

context.Set<Category>().Add(cat_0);

When I save the cat_0 to the database only 1 row is inserted and Entity Framework does not pick up the fact the cat_0 is the parent of a whole bunch of other objects and does not realise that they need to be persisted. I have a workaround which is the commented out code in the "Parent" category property.. but I would rather not have to do this as is does not feel right.

Any help would be much appreciated

Jake

+1  A: 

It is possible but you have to use tracking proxies. To do that modify your Category class so that all persisted properties are virtual.

public class Category 
{ 
    public virtual int Id { get; set; } 
    public virtual string Name { get; set; } 
    public virtual Category Parent { get; set; }
    public virtual ICollection<Category> Children { get; set; } 
} 

Create context and check that creation of dynamic proxy is allowed. On such context you can use CreateObject method to get your category instance. You will not get instance of type Category but dynamic type inherited from Category. This dynamic proxy is responsible for lazy loading (if enabled) and for change tracking to existing context. If you modify navigation property on the one side it will automatically modify navigation property on the other side.

using (var context = new ObjectContext(connectionString))
{
  // This should be default value
  context.ContextOptions.ProxyCreationEnabled = true;

  var cat0 = context.CreateObject<Category>();
  cat0.Name = "A";

  var cat1 = context.CreateObject<Category>();
  cat1.Name = "B";
  cat1.Parent = cat0;

  context.CreateObjectSet<Category>().AddObject(cat0);
  context.SaveChanges(); 
}

Edit:

If you don't like approach with tracking proxies (which require existing context) you can reverse the way you create your entities. Instead of setting Parent property on childs you have to fill Childs on parent. In that case it will work.

Ladislav Mrnka
Yeah thanks for the answer yeah I kinda guessed that the ObjectContext would have to know about the entity when created. Also I am using the DbContext class which has the ObjectContext as a protected property not sure what the reasoning is behind hiding all the functionality that ObjectContext exposes. Would like to hear any feedback as to why that is.. :)
Jake Scott