IMHO, one of the most brilliant DDD concept is the ability of separate contexts in a application. But I'm confused on how I can put everything to work together.
First, I know that one thing is not related to other. But my question falls exactly on the Infrastructure/ORM part.
For example, I have a domain object called Procedure (a medical procedure). In the Context of Registration, only thing that matters is Code and Name. But in Procedure Management Context, I have a lot of other fields like Price that belongs to this context specific.
How I can have two entities with same name (in different contexts) with different properties using EF Code First? Basically, I want to save all fields in the same table, but retrieve only 2 fields in one context, and all fields in other. How I can achieve this?
The following is inspired by the Shrink EF Models with DDD Bounded Contexts article.
Domain models:
namespace SO25454395.Domain.Registration
{
using System;
public class Procedure
{
public int Id { get; set; }
public Guid Code { get; set; }
public string Name { get; set; }
}
}
.
namespace SO25454395.Domain.ProcedureManagement
{
using System;
public class Procedure
{
public int Id { get; set; }
public Guid Code { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
Bounded contexts:
namespace SO25454395.Infrastructure
{
using System.Data.Entity;
public class RegistrationContext : BaseContext<RegistrationContext>
{
public DbSet<Domain.Registration.Procedure> Prodedures { get; set; }
}
}
.
namespace SO25454395.Infrastructure
{
using System.Data.Entity;
public class ProcedureManagementContext : BaseContext<ProcedureManagementContext>
{
public DbSet<Domain.ProcedureManagement.Procedure> Procedures { get; set; }
}
}
The default Code First behavior is to create a new database for each context, so we disable this using a base class and specify the database that should be shared among all contexts.
namespace SO25454395.Infrastructure
{
using System.Data.Entity;
public class BaseContext<TContext> : DbContext where TContext : DbContext
{
static BaseContext()
{
Database.SetInitializer<TContext>(null);
}
protected BaseContext() : base("Database")
{
}
}
}
Finally we need a context containing all classes used to build the complete model. This context is used for initialization.
namespace SO25454395.Infrastructure
{
using SO25454395.Domain.ProcedureManagement;
using System.Data.Entity;
public class DatabaseContext : DbContext
{
public DbSet<Procedure> Procedures { get; set; }
public DatabaseContext() : base("Database")
{
}
}
}
Test:
namespace SO25454395.Tests
{
using SO25454395.Infrastructure;
using System;
using System.Linq;
using Xunit;
public class BoundedContextTests
{
[Fact]
public void Test()
{
using (var databaseContext = new DatabaseContext())
{
databaseContext.Database.Initialize(true);
}
var code = Guid.NewGuid();
var name = "Name";
var price = 123.45m;
using (var procedureManagementContext = new ProcedureManagementContext())
{
var procedure = new Domain.ProcedureManagement.Procedure { Code = code, Name = name, Price = price };
procedureManagementContext.Procedures.Add(procedure);
procedureManagementContext.SaveChanges();
}
using (var registrationContext = new RegistrationContext())
{
var procedure = registrationContext.Prodedures.Single(p => p.Code == code);
Assert.Equal(name, procedure.Name);
// procedure.Price is not available here.
}
}
}
}