8

I'm trying to seed my database with some test data with an IDatabaseIntialiser like this:

protected override void Seed(BlogDataContext context)
{
    // <snip>
    var post = context.Posts.Create();
    post.Title = "My Life On Twitter";
    // <snip properties>

    // Set tags
    post.Tags.Add(aspnetTag); // NullRefException
    post.Tags.Add(razorTag);

Post entity looks like this:

public class Post
{
    // ...
    public virtual ICollection<Tag> Tags { get; set; }

Full entities at Bitbucket: Post and Tag. All code is at http://code.dantup.com/blog

However, post.Tags is null, so this doesn't work. Originally I was creating post as new Post(), however since I'm calling the Create method provided by the EF, why is the collection not initialised?

It feels clumsy to instantiate my own collection here, and if I do it in the constructor, presumably every time I load an entity from EF, it'll create the collection in the constructor and then overwrite it with one containing the actual data from the DB?

Is there some way to tell EF to create me an entity, including collections/proxies for my ICollections (assuming ICollection is the right choice)?

Edit: context.Configuration.ProxyCreationEnabled is set to true (by default), which seems to exist for this reason?

CraigTP
  • 44,143
  • 8
  • 72
  • 99
Danny Tuppeny
  • 40,147
  • 24
  • 151
  • 275
  • look here: http://prodinner.codeplex.com/ in the source code, no collection initialization is needed with EF4.1 CodeFirst POCOs at least – Omu May 12 '11 at 18:09
  • http://code.google.com/p/prodinner/source/browse/trunk/Core/Model/DelEntity.cs – Omu May 12 '11 at 18:10
  • @Omu - I'm using EF4.1, but the collections are null upon creation, but look the same as theirs – Danny Tuppeny May 12 '11 at 18:12
  • can you show us your entities ? – Omu May 12 '11 at 18:13
  • I posted the relevant part, but if you want to see the full files https://bitbucket.org/DanTup/dantup-blog/src/03cfceba726b/DanTup%20Blog/Models/Post.cs https://bitbucket.org/DanTup/dantup-blog/src/03cfceba726b/DanTup%20Blog/Models/Tag.cs All code is at http://code.dantup.com/blog – Danny Tuppeny May 12 '11 at 18:15
  • you need to do post.Tags = new List(); it's not initialized because it's a new object, and reference types are null by default – Omu May 12 '11 at 18:23
  • and proxy creation has nothing to do with this – Omu May 12 '11 at 18:57
  • @Omu This is what I'm trying to avoid - I'm asking the EF to create my entity (.Posts.Create()), and it makes sense that I can have the collections initialised in the same way as when loading entities. Initialising them myself would mean there's no change-tracking like on a fetched entity. I'm sure there must be a way to have EF generate the collection. – Danny Tuppeny May 12 '11 at 19:25
  • @Danny Typpeny why would you need change tracking on something that isn't persisted yet, when you do .SaveChanges() it's clear that it's a new object, and everything has to be inserted (INSERT) into the Db – Omu May 13 '11 at 06:51
  • @Omu The entities I'm adding to the collection (many-to-many relationship) are already persisted, and I was under the impression EF would maintain the collections on both entities for me – Danny Tuppeny May 13 '11 at 07:24
  • so if you take an existing entity, add it to a collection that you created via net List<>(), and do .SaveChanges(), is it going to be an insert for that entity ( and you would get some error that it cannot insert value for the ID field or something similar) – Omu May 13 '11 at 07:31
  • Calling SaveChanges would save the new entity, then insert records in the link table for the relationship to the (pre-existing) entities added to the collection. – Danny Tuppeny May 13 '11 at 07:58
  • so everything looks ok, is there any functionality that you loose by doing new List<>() – Omu May 13 '11 at 08:58
  • Well I assumed that many-to-many relationships would be maintained by EF (eg. when I add to one side, it's added to the other, without having to reload). That won't be the case if I create the list myself (though I haven't actually tested it works with fetched entities, I may be mistaken). – Danny Tuppeny May 13 '11 at 10:46
  • Dupe? http://stackoverflow.com/questions/4526364/entity-framework-uninitialised-collection – Wolfwyrd Mar 06 '13 at 09:19
  • Also - http://stackoverflow.com/questions/5703761/entity-framework-4-1-code-first-should-many-relationship-icollections-be-initi – Wolfwyrd Mar 06 '13 at 09:22
  • @Wolfwyrd Neither of those questions have valid answers either :( – Danny Tuppeny Mar 06 '13 at 11:07

1 Answers1

6

With POCO entities and EF, I generally initialize collection in the constructor. And, I prefer ISet over ICollection ;-)

Fabian Vilers
  • 2,892
  • 2
  • 24
  • 30
  • What do you initialise it to? It feels clumsy, as the EF will initialise things differently when loading (maybe with a proxy). I'd like to know if can make it the same. Also - ISet vs ICollection - I keep googling but can't find any info which collections are best with EF and for what reason :( – Danny Tuppeny May 12 '11 at 18:06
  • 1
    If I use an ISet, I'll instantiate a HasSet. I suppose EF is smart enougth to check that the collection has been initiliazed when it tries to bind it with your entities. A set ensures that each item in its collection is unique. Collection allows multiple reference to the same object. – Fabian Vilers May 12 '11 at 18:12
  • 1
    If you look at your raw view of your ICollection after pulling it from your DbContext, you can see that EF will use HashSet to initialize your objects. I'd suggest doing the same in your property get/set. That said - I agree that this isn't satisfactory. MVC creates the objects for you, so you have to muck up your model code with EF-specific initialization. I'd prefer that this behavior was controlled via attributes. However - if you are using new() to instantiate your objects, then there is no way for EF to know about them until you put them in your ObjectContext. – Doug Sep 05 '11 at 19:11