Oblomingo
Oblomingo

Reputation: 698

How to create Value-Objects in ASP.Net MVC, Entity Framework 6 project?

There are classes in my test applications:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
        Database.SetInitializer<ApplicationDbContext>(new MovieContextInitializer());
    }

    public DbSet<Movie> Movies { get; set; }
    public DbSet<Currency> Currencies { get; set; }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Types<Movie>()
        .Configure(ctc => ctc.Property(m => m.Price.Amount).HasColumnName("MoviePriceAmount"));

        modelBuilder.Types<Movie>()
        .Configure(ctc => ctc.Property(m => m.Price.Currency.Id).HasColumnName("MoviePriceCurrency"));

        base.OnModelCreating(modelBuilder);
    }
}

MovieContextInitializer for init data:

public class MovieContextInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext>
{
    protected override void Seed(ApplicationDbContext context)
    {
        var usdCurrency = new Currency {Id = 1, Name = "USD"};
        var euroCurrency = new Currency {Id = 2, Name = "EUR"};

        context.Currencies.Add(usdCurrency);
        context.Currencies.Add(euroCurrency);

        context.Movies.Add(new Movie
        {
            Title = "GhoustBusters",
            Genre = "Comedy",
            ReleaseDate = new DateTime(2016, 9, 10),
            Price = new Money(50, usdCurrency)
        });

        context.Movies.Add(new Movie
        {
            Title = "Matrix",
            Genre = "Action",
            ReleaseDate = new DateTime(2010, 2, 10),
            Price = new Money(40, euroCurrency)
        });
    }
}

And my entity and value objects classes:

public class Movie
{
    public int Id { get; set; }
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public Money Price { get; set; }
}
public class Currency
{
    public int Id { get; set; }
    public string Name { get; set; }
}
[ComplexType]
public class Money 
{
    public Money(int amount, Currency currency)
    {
        Amount = amount;
        Currency = currency;
    }
    public int Amount { get; private set; }
    public Currency Currency { get; private set; }
}

When I am trying to call:

ApplicationDbContext db = new ApplicationDbContext();
var movies = db.Movies.ToList() 

I am getting exception: "One or more validation errors were detected during model generation: DomainDrivenWeb.Models.Currency: Name: Each type name in a schema must be unique. Type name 'Currency' is already defined.".

Upvotes: 0

Views: 550

Answers (1)

Chris Simon
Chris Simon

Reputation: 6505

The problem here is that you're treating Currency as both a ValueObject and an Entity.

This line:

modelBuilder.Types<Movie>()
    .Configure(ctc => ctc.Property(m => m.Price.Currency.Id).HasColumnName("MoviePriceCurrency"));

Tells EF that the Currency type is implicitly a Complex Type on the Move entity - nested on the Price property (of type Money). This is more like a ValueObject.

But

public DbSet<Currency> Currencies { get; set; }

Tells EF to treat it as an Entity.

This is why the error message says Each type name in a schema must be unique. Type name 'Currency' is already defined. - When it comes time to setup the model of Currency as entity, the Type Name Currency is already defined as a Complex Type on the Movie entity.

If you remove one or the other of those config lines, the error should go away - but it won't really resolve your issue, because you need to think about - is Currency in your domain truly an Entity or a ValueObject?

Movie has a Price of type Money which has a property of type Currency - this usage implies it is a ValueObject. But the class has an Id field - the presence of 'identity' implies it is an Entity.

You need to think through the domain modelling and the business processes that are embodied in these types to explore how it should really be treated.

Upvotes: 2

Related Questions