Luis Valencia
Luis Valencia

Reputation: 34038

How to associate entities during seed with Entity Framework

I have these classes:

[Serializable]
public class Module
{
        [Key]
        public int Id { get; set; }
        public string ModuleName { get; set; }
        public string FontAwesomeClass { get; set; }
}

[Serializable]
public class ModulosPorUsuario
{
        public string Email { get; set; }
        public List<Module> Modules{ get; set; }
}

And I need to seed like this:

#region Seed Modules
    context.Modulos.Add(new Module() { Id = 1, ModuleName = "Contabilidad", FontAwesomeClass = "fa-ambulance" });
    context.Modulos.Add(new Module() { Id = 2, ModuleName = "Recursos Humanos", FontAwesomeClass = "fa-heartbeat" });
    context.Modulos.Add(new Module() { Id = 3, ModuleName = "Inventario", FontAwesomeClass = "fa-anchor" });
    context.Modulos.Add(new Module() { Id = 3, ModuleName = "Produccion", FontAwesomeClass = "fa-binoculars" });
    context.Modulos.Add(new Module() { Id = 3, ModuleName = "Ventas", FontAwesomeClass = "fa-coffee" });
    context.Modulos.Add(new Module() { Id = 3, ModuleName = "Compras", FontAwesomeClass = "fa-calendar-o" });
    context.Modulos.Add(new Module() { Id = 3, ModuleName = "Cotizaciones", FontAwesomeClass = "fa-building" });
    #endregion

However my question is how can I associate a list of modules that were previously seeded??

    #region Seed ModulosPor Usuario
    context.ModulosPorUsuario.Add(new ModulosPorUsuario()
    {
        Email = "[email protected]",
        Modules = ???
    });

    #endregion

Update 1:

When I check the tables created for me this doesnt look right. A module is an entity by its own, and ModulesPeruser should be a relationship between email and many different modules. However on the Module table it created a foreign key to ModulesPerUser.

What is wrong with my design? http://screencast.com/t/Z0u2950zm

Upvotes: 1

Views: 237

Answers (4)

Chris Pratt
Chris Pratt

Reputation: 239440

Couple of things to be aware of:

  1. Seeding runs every time you update the database. As a result, you should use AddOrUpdate, rather than Add, to keep from adding the same items multiple times.

  2. When using AddOrUpdate, only simple data types are updated (string, int, etc.). Properties referencing class instances or list properties will not be updated.

To get around the second point, you should update id properties rather than reference properties. For example, given the following:

public class Foo
{
    public int Id { get; set; }

    public string Name { get; set; }

    public int BarId { get; set; }
    public virtual Bar Bar { get; set; }
}

public class Bar
{
    public int Id { get; set; }

    public string Name { get; set; }

    public virtual ICollection<Foo> Foos { get; set; }
}

You would need to structure your seed like:

var bar1 = new Bar { Name = "Bar 1" };
var bar2 = new Bar { Name = "Bar 2" };
var bar3 = new Bar { Name = "Bar 3" };

context.Bars.AddOrUpdate(
    r => r.Name,
    bar1,
    bar2,
    bar3
 );

 context.SaveChanges();

 context.Foos.AddOrUpdate(
     r => r.Name,
     new Foo
     {
         Name = "Foo",
         BarId = bar1.Id
     }
  );

That way, if you want to change the Bar instance, the Foo is associated with, you can. If you were to use Bar = bar1 instead, it would be ignored on update.

The same goes for your list properties. In a one-to-many situation, you should set the relationship on the principal side as in the sample code above, rather than setting the list property directly, Bar.Foos in this example.

In a many-to-many, you simply won't be able to update the relationship, since both sides have a collection and you don't have any access to the join table. You can initially seed the relationships, but you won't be able to update them in future seeds.

Upvotes: 0

JamieD77
JamieD77

Reputation: 13949

var modules = new List<Module>()
{
    new Module() { Id = 1, ModuleName = "Contabilidad", FontAwesomeClass = "fa-ambulance" },
    new Module() { Id = 2, ModuleName = "Recursos Humanos", FontAwesomeClass = "fa-heartbeat" },
    new Module() { Id = 3, ModuleName = "Inventario", FontAwesomeClass = "fa-anchor" },
    new Module() { Id = 4, ModuleName = "Produccion", FontAwesomeClass = "fa-binoculars" },
    new Module() { Id = 6, ModuleName = "Ventas", FontAwesomeClass = "fa-coffee" },
    new Module() { Id = 7, ModuleName = "Compras", FontAwesomeClass = "fa-calendar-o" },
    new Module() { Id = 8, ModuleName = "Cotizaciones", FontAwesomeClass = "fa-building" }
};

context.ModulosPorUsuario.Add(new ModulosPorUsuario()
{
    Email = "[email protected]",
    Modules = modules
});

context.SaveChanges();

Upvotes: 0

Arnel
Arnel

Reputation: 332

You can save the list of modules and after call dbContext.SaveChanges()assign that collection to the modulosPorUsuario object and save changes again.

Upvotes: 0

TakeMeAsAGuest
TakeMeAsAGuest

Reputation: 995

var module1 = new Module() { Id = 1, ModuleName = "Contabilidad", FontAwesomeClass = "fa-ambulance" };
context.Modulos.Add(module);
context.ModulosPorUsuario.Add(new ModulosPorUsuario()
{
    Email = "[email protected]",
    Modules = new List<Module>(){module1, module2 etc...};
});

Upvotes: 2

Related Questions