How can I model this object hierarchy in Fluent NHibernate without violating DDD principles? - nhibernate

I am trying to build a domain model that will allow me to manage Contracts.
The Contract class is my aggregate root, and it has a single property right now, which is Reviewers.
Reviewers, in the context of the Contract, each have a property to it's parent Contract, and a First Name, Last Name, and Login. The reason they have these properties is so I can have the user select which Reviewers they want on a Contract.
The database that I'm tying my domain model to already exists, and it's a legacy system that I'm trying to extend.
It has a Contract Table, and a Reviewer Table.
The thing I haven't mentioned up until this point, is that Reviewers are actually Users in the system. So there's actually a third table involved, which is Users.
I have been able to map my Contract Table easily with FNH.
It looks something like this:
public class ContractMapping: ClassMap<Contract>
{
public ContractMapping()
{
Id(c => c.Id);
HasMany(c => c.AdditionalReviewers);
}
}
But I'm not sure how to model my Reviewers, because they are in fact Users as well. So my object model looks like this:
public class Reviewer: User
{
public virtual Guid Id { get; set; }
public virtual Contract Contract { get; set; }
}
public class User
{
public virtual Guid Id { get; set; }
public virtual string Login { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
}
I've been able to map my User class properly, and it looks something like this:
public class UserMapping: ClassMap<User>
{
public UserMapping()
{
Id(u => u.Id);
Map(u => u.Login);
Map(u => u.FirstName);
Map(u => u.LastName);
}
}
and I believe I want to map my Reviewer class like this:
public class ReviewerMapping: SubclassMap<Reviewer>
{
public ReviewerMapping()
{
Table("Reviewer");
//Id(r => r.Id).Column("ReviewerId"); <- won't compile
References(r => r.Contract).Column("ContractId");
}
}
So the problem I'm having is this:
The relationship between the User table and the Reviewer table is one to many. Meaning, for a given User there may be many Reviewer records. Why? Because a User has to be a Reviewer for a specific Contract. This causes an issue with the mapping, though, because the primary key for my Reviewer and the primary key for my User are completely different values, by necessity.
Also, because of the way I'm using Reviewer, when I create a new Reviewer, what I'm really trying to do is to associate a User with a Contract. I am not trying to create an entirely new User in the database.
What is the correct way for me to map Reviewer, knowing that in my domain model it is a subclass of User?

Sounds like a the Reviewer is not really modelling a person, but modelling a role or assignment the User takes on. I'd say your domain model is flawed in this aspect. Tweak Reviewer to be an association class between a User and a Contract.

I don't think Reviewer should inherit from User in the scenario you've described. I would have the Reviewer class hold a User object instead (composition over inheritance).
If it helps you conceptualize it better, rename Reviewer to Review. That way you can stop thinking about it as a User since it really isn't (multiple Reviewers in your current domain can be the same User, which doesn't make much sense).

Related

nhibernate one-to-many collection- retrieve only the superclass

I have the following classes:
class Person
{
public string Name { get; set; }
}
class Employee : Person
{
public int Salary { get; set; }
}
class Company
{
public IList<Person> PeopleWhoAreNotEmployees { get; set; }
}
Person and Employee are mapped using table-per-class-heirarchy strategy.
When I retrieve the PeopleWhoAreNotEmployees collection, I want it only to contain elements that are Person, and NOT Employees.
How can I (fluently) configure the collection to only retrieve elements of the super class?
I think it's something to do with the Polymorphism property, but I couldn't really figure out how to do that.
thanks,
Jhonny
EDIT:
following the discussion with Jamie, I feel I need to clarify that the case here isn't really Person and Employee, but more like Employee and HistoricalEmployee.
Meaning- when an employee 'dies', they're not really deleted, but they become HistoricalEmployee (with a few more attributes, such as termination date etc.).
Obviously, over time, the number of HistoricalEmployees will exceed the number of Employees by magnitudes, so I can't fetch all HistoricalEmployees when I only need current Employees.
Sorry for the ambigiuity of the original question...
J
P.S. I didn't change the original question since it would make the answer irrelevant. a new version of this question is available here
I don't think you can, but that's not how I would approach it anyway. I would use a private field for the collection and expose methods that filter the list. This is much easier to map and work with and performance will be fine if the collection is reasonably sized (I don't know what's reasonable but I wouldn't worry about it if it's < 1000). It would make it easier if you had an abstract PersonBase class that both Person and Employee extend so that you don't have to deal with uncertainty that a Person might be an Employee.
public class Company
{
private IList<Person> _allPeople;
public IEnumerable<Employee> Employees()
{
return _allPeople.OfType<Employee>();
}
public IEnumerable<Person> PeopleWhoAreNotEmployees()
{
return _allPeople.Where(x => !(x is Employee));
}
}
EDIT:
In response to your comment, the filtering would take place in the class. The private collection would cause all the People to be loaded, and the properties would dynamically filter that collection. The mapping wold look like:
public class CompanyMap : ClassMap<Company>
{
public CompanyMap ()
{
// only collection is shown w/o cascade option
HasManyToMany(x => x.Person).Access.CamelCaseField(Prefix.Underscore);
}
}
what I ended up doing was using a 'where' clause on my property.
the fluent configuration looks like so:
mapping.HasMany(x => x.Employees)
.Where("IsFired = 0")

Inheritance with Fluent NHibernate produces double results

I have the following scenario:
public class Login
{
public virtual int Id { get; set; }
public virtual string Username { get; set; }
}
public class User : Login
{
public IList<Account> Accounts { get; set; }
}
If I have two maps (ClassMap<Login> and ClassMap<User>), all queries returns double results - one per maps I'd guess.
Is it possible to avoid this? I don't have a discriminator value. There are a lot more properties on the user, so I'd like to be able to just get a sub set of these via the login.
Since User extends Login, querying Login will, by default, return User instances too.
To avoid this, polymorphism="explicit" must be used in the XML mappings.
For Fluent mappings, use Polymorphism.Explicit().
Perhaps specifying different data tables for the two entities Login and User might do the trick, so you would have to explicitely query either the Login or User depending on your needs. Otherwise, Diego Mijelshon's answer sounds pretty good!

nHibernate mapping for entity to multiple different parent entities (eg Addres -> Firm, Addres -> Client)

Can someone help me with the best way to map the following situation in fluent nHibernate? The Address class is used in both Client and Company. How can I store it most efficient in SQL? And what should the mapping look like? I've thought about multiple options, but I'm not experienced enough with nHibernate for these situations:
use 1 address entity and 1 table and use a denominator column to distinguish between address for client and address for company -> how to implement this in nHibernate?
use 1 address entity and 2 tables (ClientAddresses and CompanyAddresses) --> but I can only define 1 table in the mapping of the class Address
use 2 address entities and 2 tables --> not so elegant
I've just stumbled upon this problem when I started implementing the company class and realized it also needed multiple addresses. Up till now I had a Address and Client class and had a one-to-many mapping between them. In the database the Address had an extra column called ClientId. But with introducing the Company class I'm stuck...
Any help would greatly be appreciated.
I'm currently working in the sharparch 1.5 framework, which uses automapping and my mapping files are like this:
public class AddressMap : IAutoMappingOverride<Address>
{
public void Override(AutoMapping<Address> mapping)
{
mapping.Table("addresses");
mapping.Id(x => x.Id, "AddressGuid")
.UnsavedValue(Guid.Empty)
.GeneratedBy.GuidComb();
mapping.References(x => x.Client, "ClientGuid");
}
}
Below some more code the illustrate the problem:
Address
public class Address
{
public virtual string StreetLine1 { get; set; }
public virtual string StreetLine2 { get; set; }
public virtual string PostalCode { get; set; }
public virtual string City { get; set; }
public virtual string Country { get; set; }
}
which has the following table:
tablename = addresses
fields= AddressGuid, StreetLine1, StreetLine2, PostalCode, City, Country
Client
public class Client
{
public IList<Address> Addresses {get;set;}
}
Company
public class Company
{
public IList<Address> Addresses {get;set;}
}
It looks like you can implement #1 with nHibernate's <any> mapping. Note that in this case you cannot specify foreign-key constraints.
an example of <any>
Fluent nHibernate syntax
You could model the relationships as a many-to-many: many companies to many addresses, and many clients to many addresses.
In both your Company and Client mappings:
mapping.HasManyToMany(x => x.Addresses);
This will create two additional tables: one mapping between companies and addresses, another mapping between clients and addresses.
In theory this could allow sharing situations (some companies and clients all sharing have the same address row) which you probably don't want, but as long as your application logic doesn't allow that to happen, you'll be fine and you won't have to do anything tricky with nhibernate.

Advise on object-oriented design

I would like some help with a OOD query.
Say I have the following Customer class:
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
It's a simple placeholder for customer related data. Next comes the CustomerFactory, which is used to fetch customers:
public static class CustomerFactory
{
public static Customer GetCustomer(int id)
{
return null; // Pretend this goes off to get a customer.
}
}
Now, if I wanted to write a routine named UpdateCustomer(Customer customer) can someone suggest where I could place this method?
Obviously I don't want to use the Customer class since that would be against SRP (Single Responsibility Principle), also I don't see it as a good idea to attach the method to the CustomerFactory class, since it's only role is to get customers from the database.
So it looks like I'm going to need another class, but I don't know what to name it.
Cheers.
Jas.
What you have called a Factory isn't a Factory at all. It's a Repository.
A Factory handles the instansiation of various classes sharing a common Interface or Class Hierarchy based on some set of parameters.
A Repository handles the retrieval and management of data.
The Repository would definitely have the UpdateCustomer(Customer customer) method in it as well as the GetCustomer(int id) method.
You are more on less on your way to creating a Repository. Do something like this:
public interface ICustomerRepository
{
Customer SelectCustomer(int id);
void UpdateCustomer(Customer customer);
void DeleteCustomer(int id);
void CreateCustomer(Customer customer);
}
Then create concrete implementations of this interface (the interface is really just because it's good practice to program against interfaces - you could skip it, though, although I would recommend that you keep it).
Wouldn't your UpdateCustomer routine be placed in your DAL (Data Access Layer). You should define a class to handle inserts or updates to the database and then pass a customer object to it.
You could write the DAL class to handle all of this but I don't see any issue in storing it in your CustomerFactory class, although as mentioned it is not really a factory.

Question about Repositories and their Save methods for domain objects

I have a somewhat ridiculous question regarding DDD, Repository Patterns and ORM. In this example, I have 3 classes: Address, Company and Person. A Person is a member of a Company and has an Address. A Company also has an Address.
These classes reflect a database model. I removed any dependencies of my Models, so they are not tied to a particular ORM library such as NHibernate or LinqToSql. These dependencies are dealt with inside the Repositories.
Inside one of Repositories there is a SavePerson(Person person) method which inserts/updates a Person depending on whether it already exists in the database.
Since a Person object has a Company, I currently save/update the values of the Company property too when making that SavePerson call. I insert / update all of the Company's data - Name and Address - during this procedure.
However, I really have a hard time thinking of a case where a Company's data can change while dealing with a Person - I only want to be able to assign a Company to a Person, or to move a Person to another Company. I don't think I ever want to create a new Company alongside a new Person. So the SaveCompany calls introduce unnecessary database calls. When saving a Person I should just be able to update the CompanyId column.
But since the Person class has a Company property, I'm somewhat inclined to update / insert it with it. From a strict/pure point of view, the SavePerson method should save the entire Person.
What would the preferred way be? Just inserting/updating the CompanyId of the Company property when saving a Person or saving all of its data? Or would you create two distinct methods for both scenarios (What would you name them?)
Also, another question, I currently have distinct methods for saving a Person, an Address and a Company, so when I save a Company, I also call SaveAddress. Let's assume I use LinqToSql - this means that I don't insert/update the Company and the Address in the same Linq query. I guess there are 2 Select Calls (checking whether a company exists, checking whether an address exists). And then two Insert/Update calls for both. Even more if more compound model classes are introduced. Is there a way for LinqToSql to optimize these calls?
public class Address
{
public int AddressId { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
}
public class Company
{
public int CompanyId { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public Company Company { get; set; }
public Address Address { get; set; }
}
Edit
Also see this follow up question. How are Value Objects stored in a Database?
I myself have used the IRepository approach lately that Keith suggests. But, you should not be focusing on that pattern here. Instead, there are a few more pieces in the DDD playbook that can be applied here.
Use Value Objects for your Addresses
First, there is the concept of Value Objects (VO) you can apply here. In you case, it would be the Address. The difference between a Value Object and an Entity Object is that Entities have an identity; VOs do not. The VO's identity really is the sum of it's properties, not a unique identity. In the book Domain-Drive Design Quickly (it's also a free PDF download), he explains this very well by stating that an address is really just a point on Earth and does not need a separate SocialSecurity-like identity like a person. That point on Earth is the combination of the street, number, city, zip, and country. It can have latitude and longitude values, but still those are even VOs by definition because it's a combination of two points.
Use Services for combining your entities into a single entity to act upon.
Also, do not forget about the Services concept in the DDD playbook. In your example, that service would be:
public class PersonCompanyService
{
void SavePersonCompany(IPersonCompany personCompany)
{
personRepository.SavePerson();
// do some work for a new company, etc.
companyRepository.SaveCompany();
}
}
There is a need for a service when you have two entities that need both need a similar action to coordinate a combination of other actions. In your case, saving a Person() and creating a blank Company() at the same time.
ORMs usualyl require an identity, period.
Now, how would you go about saving the Address VO in the database? You would use an IAddressRepository obviously. But since most ORMs (i.e. LingToSql) require all objects have an Identity, here's the trick: Mark the identity as internal in your model, so it is not exposed outside of your Model layer. This is Steven Sanderson's own advice.
public class Address
{
// make your identity internal
[Column(IsPrimaryKey = true
, IsDbGenerated = true
, AutoSync = AutoSync.OnInsert)]
internal int AddressID { get; set; }
// everything else public
[Column]
public string StreetNumber { get; set; }
[Column]
public string Street { get; set; }
[Column]
public string City { get; set; }
...
}
From my recent experience of using the repository pattern I think you would benefit from using a generic repository, the now common IRepository of T. That way you wouldn't have to add repository methods like SavePerson(Person person). Instead you would have something like:
IRepository<Person> personRepository = new Repository<Person>();
Person realPerson = new Person();
personRepository.SaveOrUpdate(realPerson);
This method also lends itself well to Test Driven Development and Mocking.
I feel the questions about behavior in your description would be concerns for the Domain, maybe you should have an AddCompany method in your Person class and change the Company property to
public Company Company { get; private set; }
My point is; model the domain without worrying about the how data will be persisted to the database. This is a concern for the service that will be using your domain model.
Back to the Repository, have a look at this post for good explanation of IRepository over LinqToSql. Mike's blog has many other posts on Repositories. When you do come to choose an ORM I can recommend HHibernate over LinqToSql, the latter is now defunct and NHibernate has a great support community.