HaakonL
HaakonL

Reputation: 127

EF, Code First, WCF => empty collection problem

I am having some problems with the Ef 4.1 code first implementation.

public class Foo()
{
    public Foo()
    {
        Id = Guid.NewGuid();
        Bars = new Collection<Bar>();
    }

    public Guid Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection Bars { get; set; }
}

public class Bar()
{
    public Bar()
    {
        Id = Guid.NewGuid();
    }

    public Guid Id { get; set; }
    public string Name { get; set; }
    public virtual Foo Foo { get; set;}
}

public class MyContext : DbContext
{
    public MyContext()
    {
        Configuration.ProxyCreationEnabled = false;
    }

    public DbSet<Foo> Foos { get; set; }
    public DbSet<Bar> Bars { get; set; }
}

When I put a wcf service on top of this, it only returns an empty collection of Bars. If I turn on the ProxyCreationEnabled, the collection will be filled, but then I will get wcf exceptions and closed connections because of the EF proxy creation.

Any suggestions?

Upvotes: 3

Views: 2056

Answers (1)

Ladislav Mrnka
Ladislav Mrnka

Reputation: 364349

You must use eager loading if you want to load Bars as well. EF never loads related objects by itself. You must always ask EF for related objects either by eager loading or lazy loading. If you turn on proxy creation EF will try to load Bars collection by lazy loading during data serialization (first time the collection is accessed) but you will either get exception because of closed context or because of cycle in serialized data (Bar.Foo and Foo.Bars create cycle).

To use eager loading you must add Include method to your query:

var data = context.Foos.Include(f => f.Bars).ToList();

To avoid cycles you must either remove Foo in Bar or mark Foo and Bar with DataContract with IsReference=true and DataMember attributes:

[DataContract(IsReference=true)]
public class Foo()
{
    public Foo()
    {
        Id = Guid.NewGuid();
        Bars = new Collection<Bar>();
    }

    [DataMember]
    public Guid Id { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public virtual ICollection Bars { get; set; }
}

[DataContract(IsReference=true)]
public class Bar()
{
    public Bar()
    {
        Id = Guid.NewGuid();
    }

    [DataMember]
    public Guid Id { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public virtual Foo Foo { get; set;}
}

Or you will have to mark Foo property in Bar as not serialized to break a cycle:

public class Bar()
{
    public Bar()
    {
        Id = Guid.NewGuid();
    }

    public Guid Id { get; set; }
    public string Name { get; set; }
    [IgnoreDataMember]
    public virtual Foo Foo { get; set;}
}

Upvotes: 6

Related Questions