I'm developing an application that implements DDD and Repository Pattern as shown in diagram bellow:
I expect to keep my Domain Layer persistent ignorant, so I wouldn't like to install entity framework libraries there. The only problem I'm facing is that my application uses spatial data, but I'm not supposed to use DbGeography as a Property Type of my entities, once it belongs to System.Data.Entity.Spatial namespace, from EntityFramework assembly.
Is there a way to create a class to hold latitude, longitude and elevation values in Domain Layer, like that:
public class Location
{
public double Latitude { get; set; }
public double Longitude { get; set; }
public double Elevation { get; set; }
}
and then convert that class to DbGeography in my Repository Layer?
In other words, the domain entities would have only Location class as a property:
public class Place : IEntityBase, ILocalizable
{
public int Id { get; set; }
public string Name { get; set; }
public Location Location { get; set; }
public User Owner { get; set; }
}
and I'd convert it DbGegraphy to persist spatial data and do some calculations only in repository layer. My plans was try something like that to convert:
public class LocationMap : ComplexTypeConfiguration<Location>
{
public LocationMap()
{
Property(l => DbGeography.FromText(string.Format("POINT({0} {1})", l.Longitude, l.Latitude))).HasColumnName("Location");
Ignore(l => l.Elevation);
Ignore(l => l.Latitude);
Ignore(l => l.Longitude);
}
}
But it doesn't work and never will. How I can solve this problem? What are the best practices in this situation?
Thank you
Well, I don't know "right" way, but, i have a tricky idea. I hope, it'll help you or give some more variants:
Ypu have domain entity Place, it's fully persistent ignorant and it's place in Domain assembly. Good.
Lets create one more Place class in Repository assembly:
internal sealed class EFPlace : Place
{
DbGeography EFLocation
{
get
{
return DbGeography.FromText(string.Format("POINT({0} {1})", Location.Longitude, Location.Latitude);
}
set
{
//vice versa convertion, I don't know, how to do it :)
}
}
}
We created special class for Entity Framework, and map it:
public class PlaceMap : ComplexTypeConfiguration<EFPlace>
{
public PlaceMap ()
{
Property(p => p.EFLocation).HasColumnName("Location");
Ignore(p => p.Location);
}
}
But, we have to convert from Place to EFPlace on save in repository. You can create special constructor, or casting method.
Another variant - create partial class Place in Domain and Repository assemblies. And add needed propery in Repository one class and so on.
Well, it looks ugly :( but, I don't know "pure", real-life examples of Persistent Ignorant Domain. We always have limitations of Entity Framework. NHibernate has a little more features.
Related
I need some advice on the a question I have been battling with on DDD .
I have a domain model which is a aggregate root
public class Objective {
public int ObjectiveId { get; private set; }
public string ObjectiveDescription { get; private set; }
public DateTime StartDate { get; private set; }
public DateTime TargetDate { get; private set; }
public DateTime? CompletedDate { get; private set; }
public int EmploymentId { get; private set; }
public List<Skill> RelatedSkills { get; private set; }
public List<Goal> RelatedGoals { get; private set; }
// few more properties.
}
I have 2 views one is a List View and another is a details View.
The List View has a IEnumerable which has just 3 fields
class ObjectiveListVM{
public int ObjectiveId { get; private set; }
public string ObjectiveDescription { get; private set; }
public DateTime StartDate { get; private set; }
}
The Details view has a ObjectiveDetailViewModel which has 90 percent of the fields from the Objective domain model plus a few more.
I have a repository which gets me either a list or one objective
IObjectiveRepo
{
Objective GetById();
IEnumerable<Objective> GetList();
}
This is how I have implemented DDD and Repository pattern.
My question is this , my GetList query is really expensive , it only needs data from 3 columns but since my Repositories should always return domain objects , I End up returning a list the entire Objective domain object which has child lists and lots of fields.
The solution I thought of is to have another ObjectiveSummary domain model which just has a few fields and is returned by the GetList repo method. But it then breaks some other principles of DDD mainly that ObjectiveSummary is a Anemic Domain model . In fact its not really a model , its more of a DTO in my head.
This is such a common scenario that I feel I am missing something very basic in my implementation or interpretation of DDD / repository patterns .
Can some of the experts point out the mistake i have made in the implementation or highlight a way to address this problem without expensive queries ?
Note : I can thinka few ways of getting around this problem.But I am more interested in finding the correct way which does not break the principles of the architecture/pattern that I am using.
You should not query your domain model. An aggregate is always loaded in its entirety so it does not lend itself well to querying.
As soon as you think about lazy-loading you are probably not using an optimal approach. Lazy-loading is evil. Don't do it :)
What you are after is a query layer of sorts. This is directly related to CQRS. The query side only returns data. It has no behaviour and you return the most basic structure that you can. In the C# world that I am also in I use a DataRow or IEnumerable<DataRow>. If it is really complex I may opt for a DTO:
public interface IObjectiveQuery
{
DataRow ForList(int id);
bool Contains(string someUniqueKey);
IEnumerable<DataRow> Search(string descriptionLike, DateTime startDate);
string Description(int id);
}
Give it a go. I think you'll find it simplifies things immensely. Your domain should only be concerned about the command/write side of things.
One way to deal with it is to return IQueryable<Objective> from your repository instead of IEnumerable<Objective>.
public interface IObjectiveRepository
{
Objective GetById();
IQueryable<Objective> GetList();
}
It will allow you to keep the repository simple and add more logic to the queries in application/domain layer without performance loss. The following query will be executed on the db server, including the projection to ObjectiveListVM:
public IReadOnlyList<ObjectiveListVM> GetSummaryList()
{
return _repository
.GetList()
.Select(o => new ObjectiveListVM
{
ObjectiveId = o.ObjectiveId,
ObjectiveDescription = o.ObjectiveDescription,
StartDate = o.StartDate
})
.ToList();
}
You can use Automapper's Queryable extensions to make the projection to VMs easier.
return _repository
.GetList()
.ProjectTo<ObjectiveListVM>()
.ToList();
I've created a custom user inheriting from IdentityUser called Contacts, and my applications dbcontext inherits from IdentityDbContext like so:
public class Contact : IdentityUser<int, ContactLogin, ContactRole, ContactClaim>
{
public Contact()
{
}
}
public class dbcontext : IdentityDbContext<Contact, Role, int, ContactLogin, ContactRole, ContactClaim>
{
public dbcontext()
: base("dbcontext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// IdentityDbContext base - must be called prior to changing identity configuration
base.OnModelCreating(modelBuilder);
// custom identity table names and primary key column Id names
modelBuilder.Entity<Contact>().ToTable("Contacts").Property(p => p.Id).HasColumnName("ContactId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<ContactRole>().ToTable("ContactRoles");
modelBuilder.Entity<ContactLogin>().ToTable("ContactLogins");
modelBuilder.Entity<ContactClaim>().ToTable("ContactClaims").Property(p => p.Id).HasColumnName("ContactClaimId");
modelBuilder.Entity<Role>().ToTable("Roles").Property(p => p.Id).HasColumnName("RoleId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
By default IdentityDbContext contains a Users DbSet. Is it possible to change the name of this DbSet to match the type that it's implementing, e.g Contacts?
It's not a big deal, but it would just be nice to refer to the DbSet using dbcontext.Contacts instead of dbcontext.Users.
Thanks.
The base IdentityDbContext uses: public virtual IDbSet<TUser> Users { get; set; } to expose the Users DbSet.
You'll need a similar property for your own implementation, e.g: public IDbSet<Contacts> Contacts { get; set; }
Update
Question was regarding renaming the existing DbSet of Contacts from Users to Contacts.
No, you can't do this out of the box. You could attempt to wrap it and expose it again, but this isn't really the right thing to do. See this question for an in depth discussion.
Just a note that if you decide to overwrite anything or add your own, the default EF implementation of UserStore will use the DbSet named Users. Just something to keep an eye on if you get unexpected behavior.
Generally what I tend to do is have a big separation of concerns right.
So I have:
public IDbSet<User> Users { get; set; }
This represents anyone who wants to log into my system. So now I want to model actual concepts into my database, concepts that relate to real world things. So I have a system administrator for example, I will create an entity for this.
public class SystemAdministrator
{
public string Name { get; set; }
public int LocationId { get; set; } // a complex representation of where this administrator works from
public int UserId { get; set; } // this is now a reference to their log in
}
Now my context will look like this:
public IDbSet<User> Users { get; set; }
public DbSet<SystemAdministrator> SystemAdministrators { get; set; } // I use DbSet because it exposes more methods to use like AddRange.
This means now my database has proper representations of real world concepts which is easy for everyone to develop against. I do the same for Clients or Employees.
This also means that I can move away from primitive obsession
Assume the following simple POCOs, Country and State:
public partial class Country
{
public Country()
{
States = new List<State>();
}
public virtual int CountryId { get; set; }
public virtual string Name { get; set; }
public virtual string CountryCode { get; set; }
public virtual ICollection<State> States { get; set; }
}
public partial class State
{
public virtual int StateId { get; set; }
public virtual int CountryId { get; set; }
public virtual Country Country { get; set; }
public virtual string Name { get; set; }
public virtual string Abbreviation { get; set; }
}
Now assume I have a simple respository that looks something like this:
public partial class CountryRepository : IDisposable
{
protected internal IDatabase _db;
public CountryRepository()
{
_db = new Database(System.Configuration.ConfigurationManager.AppSettings["DbConnName"]);
}
public IEnumerable<Country> GetAll()
{
return _db.Query<Country>("SELECT * FROM Countries ORDER BY Name", null);
}
public Country Get(object id)
{
return _db.SingleById(id);
}
public void Add(Country c)
{
_db.Insert(c);
}
/* ...And So On... */
}
Typically in my UI I do not display all of the children (states), but I do display an aggregate count. So my country list view model might look like this:
public partial class CountryListVM
{
[Key]
public int CountryId { get; set; }
public string Name { get; set; }
public string CountryCode { get; set; }
public int StateCount { get; set; }
}
When I'm using the underlying data provider (Entity Framework, NHibernate, PetaPoco, etc) directly in my UI layer, I can easily do something like this:
IList<CountryListVM> list = db.Countries
.OrderBy(c => c.Name)
.Select(c => new CountryListVM() {
CountryId = c.CountryId,
Name = c.Name,
CountryCode = c.CountryCode,
StateCount = c.States.Count
})
.ToList();
But when I'm using a repository or service pattern, I abstract away direct access to the data layer. It seems as though my options are to:
Return the Country with a populated States collection, then map over in the UI layer. The downside to this approach is that I'm returning a lot more data than is actually needed.
-or-
Put all my view models into my Common dll library (as opposed to having them in the Models directory in my MVC app) and expand my repository to return specific view models instead of just the domain pocos. The downside to this approach is that I'm leaking UI specific stuff (MVC data validation annotations) into my previously clean POCOs.
-or-
Are there other options?
How are you handling these types of things?
It really depends on the projects architecture for what we do. Usually though.. we have services above the repositories that handle this logic for you. The service decides what repositories to use to load what data. The flow is UI -> Controller -> Service -> Repositories -> DB. The UI and/or Controllers have no knowledge of the repositories or their implementation.
Also, StateCount = c.States.Count would no doubt populate the States list anyway.. wouldn't it? I'm pretty sure it will in NHibernate (with LazyLoading causing an extra select to be sent to the DB).
One option is to separate your queries from your existing infrastructure entirely. This would be an implementation of a CQRS design. In this case, you can issue a query directly to the database using a "Thin Read Layer", bypassing your domain objects. Your existing objects and ORM are actually getting in your way, and CQRS allows you to have a "command side" that is separate and possibly a totally different set of tech to your "query side", where each is designed to do it's own job without being compromised by the requirements of the other.
Yes, I'm quite literally suggesting leaving your existing architecture alone, and perhaps using something like Dapper to do this (beware of untested code sample) directly from your MVC controllers, for example:
int count =
connection.Query<int>(
"select count(*) from state where countryid = #countryid",
new { countryid = 123 } );
Honestly, your question has gave me a food for thought for a couple of days. More and more I tend to think that denormalization is the correct solution.
Look, the main point of domain driven design is to let the problem domain drive your modeling decisions. Consider the country entity in the real world. A country has a list of states. However, when you want to know how many states a certain country has, you are not going over the list of the states in the encyclopedia and count them. You are more likely to look at the country's statistics and check the number of states there.
IMHO, the same behavior should be reflected in your domain model. You can have this information in the country's property, or introduce a kind of CountryStatistics object. Whatever approach you choose, it must be a part of the country aggregate. Being in the consistency boundary of the aggregate will ensure that it holds a consistent data in case of adding or removing a state.
Some other approaches:
If the states collection is not expected to change a lot, you can
allow a bit of denormalization - add "NumberOfStates" property to the
Country object. It will optimise the query, but you'll have to make
sure the extra field holds the correct information.
If you are using NHibernate, you can use ExtraLazyLoading - it will
issue another select, but won't populate the whole collection when
Count is called. More info here:
nHibernate Collection Count
So let's say I've got a POCO that I want EF Code First to persist to a data store:
public class Campaign
{
public string Name { get; set; }
public double GoalAmount { get; set; }
private double AmountRaised { get; set; }
public bool GoalMet
{
get
{
return AmountRaised >= GoalAmount;
}
}
}
Now, for whatever reason, I don't want the AmountRaised property to be accessible outside the object, but I do want it persisted to the data store. Is this possible with EF Code First?
You can make it internal and make sure that the project that contains the POCOs / domain objects are in the same assembly as your DbContext classes. Or you can declare "friend" assemblies in the files that contain your POCOs:
[assembly: InternalsVisibleTo("MyOther.Assembly")]
I am looking into migrate a large project to Entity Framework 4.0 but am not sure if it can handle my inheritance scenario.
I have several projects that inherit from an object in the “main” project. Here is a sample base class:
namespace People
{
public class Person
{
public int age { get; set; }
public String firstName { get; set; }
public String lastName { get; set; }
}
}
and one of the sub-classes:
namespace People.LawEnforcement
{
public class PoliceOfficer : People.Person
{
public string badgeNumber { get; set; }
public string precinct { get; set; }
}
}
And this is what the project layout looks like:
People - People.Education - People.LawEnforcement http://img51.imageshack.us/img51/7293/efdemo.png
Some customers of the application will use classes from the People.LawEnforcement and other users will use People.Education and some will use both. I only ship the assembles that the users will need. So the Assembles act somewhat like plug-ins in that they add features to the core app.
Is there anyway in Entity Framework to support this scenario?
Based on this SO question I'm think something like this might work:
ctx.MetadataWorkspace.LoadFromAssembly(typeof(PoliceOfficer).Assembly);
But even if that works then it seams as if my EDMX file will need to know about all the projects. I would rather have each project contain the metadata for the classes in that project but I'm not sure if that is possible.
If this isn't possible with entity framework is there another solution (NHibernate, Active Record, etc.) that would work?
Yes this is possible, using the LoadFromAssembly(..) method you've already found.
... but it will only work if you have an specialized model (i.e. EDMX) for each distinct type of client application.
This is because EF (and most other ORMs) require a class for each entity in the model, so if some clients don't know about some classes, you will need a model without the corresponding entities -- i.e. a customized EDMX for each scenario.
To make it easier to create a new model for each client application, if I was you I'd use Code-Only following the best practices laid out on my blog, to make it easy to grab only the fragments of the model you need actually need.
Hope this helps
Alex
Alex is correct (+1), but I'd strongly urge you to reconsider your model. In the real world, a police officer is not a subtype of a person. Rather, it's an attribute of that person's employment. I think programmers frequently tend to over-emphasize inheritance at the expense of composition in object oriented design, but it's especially problematic in O/R mapping. Remember that an object instance can only ever have one type. When that object is stored in the database, the instance can only have that type for as long as it exists, across multiple application sessions. What if a person had two jobs, as a police officer and a teacher? Perhaps that scenario is unlikely, but the general problem is more common than you might expect.
More relevant to your question, I think you can solve your actual problem at hand by making your mapped entity model more generic, and your application-specific data projections on the entities rather than entities themselves. Consider entities like:
public class JobType
{
public Guid Id { get; set; }
// ...
}
public class Job
{
public JobType JobType { get; set; }
public string EmployeeNumber { get; set; }
}
public class Person
{
public EntityCollection<Job> Jobs { get; set; }
}
Now your law enforcement app can do:
var po = from p in Context.People
let poJob = p.Jobs.Where(j => j.JobType == JobType.PoliceOfficerId).FirstOrDefault()
where poJob != null
select new PoliceOfficer
{
Id = p.Id,
BadgeNumber = poJob.EmployeeNumber
};
Where PoliceOfficer is just a POCO, not a mapped entity of any kind.
And with that you've achieved your goal of having a common data model, but having the "job type specific" elements in separate projects.