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

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")

Related

How to easily access widely different subsets of fields of related objects/DB tables?

Imagine we have a number of related objects (equivalently DB tables), for example:
public class Person {
private String name;
private Date birthday;
private int height;
private Job job;
private House house;
..
}
public class Job {
private String company;
private int salary;
..
}
public class House {
private Address address;
private int age;
private int numRooms;
..
}
public class Address {
private String town;
private String street;
..
}
How to best design a system for easily defining and accessing widely varying subsets of data on these objects/tables? Design patterns, pros and cons, are very welcome. I'm using Java, but this is a more general problem.
For example, I want to easily say:
I'd like some object with (Person.name, Person.height, Job.company, Address.street)
I'd like some object with (Job.company, House.numRooms, Address.town)
Etc.
Other assumptions:
We can assume that we're always getting a known structure of objects on the input, e.g. a Person with its Job, House, and Address.
The resulting object doesn't necessarily need to know the names of the fields it was constructed from, i.e. for subset defined as (Person.name, Person.height, Job.company, Address.street) it can be the array of Objects {"Joe Doe", 180, "ACompany Inc.", "Main Street"}.
The object/table hierarchy is complex, so there are hundreds of data fields.
There may be hundreds of subsets that need to be defined.
A minority of fields to obtain may be computed from actual fields, e.g. I may want to get a person's age, computed as (now().getYear() - Person.birtday.getYear()).
Here are some options I see:
A SQL view for each subset.
Minuses:
They will be almost the same for similar subsets. This is OK just for field names, but not great for the joins part, which could ideally be refactored out to a common place.
Less testable than a solution in code.
Using a DTO assembler, e.g. http://www.genericdtoassembler.org/
This could be used to flatten the complex structure of input objects into a single DTO.
Minuses:
I'm not sure how I'd then proceed to easily define subsets of fields on this DTO. Perhaps if I could somehow set the ones irrelevant to the current subset to null? Not sure how.
Not sure if I can do computed fields easily in this way.
A custom mapper I came up with.
Relevant code:
// The enum has a value for each field in the Person objects hierarchy
// that we may be interested in.
public enum DataField {
PERSON_NAME(new PersonNameExtractor()),
..
PERSON_AGE(new PersonAgeExtractor()),
..
COMPANY(new CompanyExtractor()),
..
}
// This is the container for field-value pairs from a given instance of
// the object hierarchy.
public class Vector {
private Map<DataField, Object> fields;
..
}
// Extractors know how to get the value for a given DataField
// from the object hierarchy. There's one extractor per each field.
public interface Extractor<T> {
public T extract(Person person);
}
public class PersonNameExtractor implements Extractor<String> {
public String extract(Person person) {
return person.getName();
}
}
public class PersonAgeExtractor implements Extractor<Integer> {
public int extract(Person person) {
return now().getYear() - person.getBirthday().getYear();
}
}
public class CompanyExtractor implements Extractor<String> {
public String extract(Person person) {
return person.getJob().getCompany();
}
}
// Building the Vector using all the fields from the DataField enum
// and the extractors.
public class FullVectorBuilder {
public Vector buildVector(Person person) {
Vector vector = new Vector();
for (DataField field : DataField.values()) {
vector.addField(field, field.getExtractor().extract(person));
}
return vector;
}
}
// Definition of a subset of fields on the Vector.
public interface Selector {
public List<DataField> getFields();
}
public class SampleSubsetSelector implements Selector {
private List<DataField> fields = ImmutableList.of(PERSON_NAME, COMPANY);
...
}
// Finally, a builder for the subset Vector, choosing only
// fields pointed to by the selector.
public class SubsetVectorBuilder {
public Vector buildSubsetVector(Vector fullVector, Selector selector) {
Vector subsetVector = new Vector();
for (DataField field : selector.getFields()) {
subsetVector.addField(field, fullVector.getValue(field));
}
return subsetVector;
}
}
Minuses:
Need to create a tiny Extractor class for each of hundreds of data fields.
This is a custom solution that I came up with, seems to work and I like it, but I feel this problem must have been encountered and solved before, likely in a better way.. Has it?
Edit
Each object knows how to turn itself into a Map of fields, keyed on an enum of all fields.
E.g.
public enum DataField {
PERSON_NAME,
..
PERSON_AGE,
..
COMPANY,
..
}
public class Person {
private String name;
private Date birthday;
private int height;
private Job job;
private House house;
..
public Map<DataField, Object> toMap() {
return ImmutableMap
.add(DataField.PERSON_NAME, name)
.add(DataField.BIRTHDAY, birthday)
.add(DataField.HEIGHT, height)
.add(DataField.AGE, now().getYear() - birthday.getYear())
.build();
}
}
Then, I could build a Vector combining all the Maps, and select subsets from it like in 3.
Minuses:
Enum name clashes, e.g. if Job has an Address and House has an Address, then I want to be able to specify a subset taking street name of both. But how do I then define the toMap() method in the Address class?
No obvious place to put code doing computed fields requiring data from more than one object, e.g. physical distance from Address of House to Address of Company.
Many thanks!
Over in-memory object mapping in the application, I would favor database processing of the data for better performance. Views, or more elaborate OLAP/datawarehouse tooling could do the trick. If the calculated fields remain basic, as in "age = now - birth", I see nothing wrong with having that logic in the DB.
On the code side, given the large number of DTOs you have to deal with, you could use classless dynamic (available in some JVM languages) or JSON objects. The idea is that when a data structure changes, you only need to modify the DB and the UI, saving you the cost of changing a whole bunch of classes in between.

Do I have to implement Add/Delete methods in my NHibernate entities?

This is a sample from the Fluent NHibernate website:
Compared to the Entitiy Framework I have ADD methods in my POCO in this code sample using NHibernate. With the EF I did context.Add or context.AddObject etc... the context had the methods to put one entity into the others entity collection!
Do I really have to implement Add/Delete/Update methods (I do not mean the real database CRUD operations!) in a NHibernate entity ?
public class Store
{
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public virtual IList<Employee> Staff { get; set; }
public Store()
{
Products = new List<Product>();
Staff = new List<Employee>();
}
public virtual void AddProduct(Product product)
{
product.StoresStockedIn.Add(this);
Products.Add(product);
}
public virtual void AddEmployee(Employee employee)
{
employee.Store = this;
Staff.Add(employee);
}
}
You don't have to do this for nhibernate, you have to do this for keep in-memory consistence and not repeat yourself.
Consistence in memory
If you have a two way relationship, lets say Order has Lines, and Line as a relationship to order. You don't want to have a reference from one side and not from the other.
If you just do:
order.Lines.Add(line);
You have made a reference from Order to Line, but Line.Order property remains null. So your in-memory instances are not consistent.
Don't Repeat Yourself
You can use the following code :
order.Lines.Add(line);
line.Order = order;
but you will be repeating yourself, so it is better to put this code in only one place, and the best place is as order.AddLine(..).
You don't have to. You could just call SomeStore.Products.Add(someProduct) directly from outside of your entity. But it's often good practice to make the collections 'read-only' from a public perspective, and using an add method in the entity for adding items.
One benefit of this is that you can put additional logic in there. For instance in your store example, you could set a 'storesStockedIn' collection (if there was such a thing) in the same method, and so keep all the logic about to creating that relationship in one place.
This isn't really a NHibernate thing, but rather an OOP thing. (Although I'm not familiar with EF - maybe it automates some of this for you). The design decisions are exactly the same as if it was just an unpersisted poco (without 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.

NHibernate one way, one-to-many, mapping question

I have a scenario in NHibernate where I have a one-to-many relationship between entities Employee and EmployeeStatus.
Employee has properties eg: ID, Name and an IList of EmployeeStatus, whilst EmployeeStatus, for the purposes of this question, just has it's own ID and some free text.
I don't need to hold a reference to Employee from EmployeeStatus, the management of status' will be done purely through the Employee entity - adding to the IList property. IE: I want to quite simply be able to do the following;
Employee e = new Employee();
e.Name = "Tony";
e.StatusList.Add( new EmployeeStatus("Status A") );
e.StatusList.Add( new EmployeeStatus("Status B") );
session.Save(e);
I've tried various methods, including creating a one way one-to-many mapping where inverse is false, cascade set to all-delete-orphan, which all looks like it should work, but it generates an exception about being unable to set the EmployeeId in EmployeeStatus. I'm led to believe that this is because NHibernate wants to do an insert with EmployeeId as NULL and then update it to the ID of the parent.
I guess I'm missing something here, so quite simply - can anyone tell me what my mapping file should look like to achieve the above?
Thanks in advance
Tony
-- edit: Heres a rough idea of the classes as requested --
public class Employee
{
private IList<EmployeeStatus> _statusList;
public Employee()
{
_statusList = new List<EmployeeStatus>();
}
public virtual int Id{ get; set; }
public virtual string Name{ get; set; }
public virtual IList<EmployeeStatus> StatusList
{
get
{
return _statusList;
}
}
}
public class EmployeeStatus
{
public virtual int Id{ get; set; }
public virtual string StatusText{ get; set; }
public EmployeeStatus()
{
}
public EmployeeStatus(string statusText)
{
StatusText = statusText;
}
}
The scenario you've described is just a basic one-to-many mapping. Here is the Fluent NHibernate mapping for this:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
WithTable("Employee");
HasMany(employee => employee.StatusList)
.Cascade.All();
}
}
You do not need to maintain a reference from EmployeeStatus back to Employee to achieve this.
Turns out that what I want to do isn't possible - you have to have a bi-directional association, and must set the child's parent reference. Not a massive problem I suppose, but didn't want to hold references in the child that I don't need within my code directly.
I may not of explained clearly, but an employee status cannot be linked to more than one employee. It's definitely 1 (employee) to many (status')
In the physical database, the status entity has an employeeID field, which isn't in the domain - IE: I hold no reference back to employee from the status entity, but the physical field should be inferred from the owner of the collection - In fact, it does do this if I set the EmployeeID field in the status table to nullable - it actually executes 2 SQL statements - an insert and then an update, the EmployeeID being set in the update.
Thanks,
Tony
Can you post the code for the classes?
Are you trying to keep a history of statuses for an Employee?
-- Edit --
Looks like you are going to need many-to-many, since the child in the relationship (EmployeeStatus) has no reference back to the parent (Employee).
-- Edit 2 --
If you want the insert to be done as 1 call to the DB, you are going to need to add an Employee property to the EmployeeStatus class, and set the Inverse=true. And I'm pretty sure that you are going to need to add some logic which sets the bi-directional relationship in the objects. I.E.
public void AddStatus(EmployeeStatus status)
{
this.StatusList.Add(status);
status.Employee = this;
}

NHibernate - Do I have to have a class to interface with a table?

I have a class called Entry. This class as a collection of strings called TopicsOfInterest. In my database, TopicsOfInterest is represented by a separate table since it is there is a one-to-many relationship between entries and their topics of interest. I'd like to use nhibernate to populate this collection, but since the table stores very little (only an entry id and a string), I was hoping I could somehow bypass the creation of a class to represent it and all that goes with (mappings, configuration, etc..)
Is this possible, and if so, how? I'm using Fluent Nhibernate, so something specific to that would be even more helpful.
public class Entry
{
private readonly IList<string> topicsOfInterest;
public Entry()
{
topicsOfInterest = new List<string>();
}
public virtual int Id { get; set; }
public virtual IEnumerable<string> TopicsOfInterest
{
get { return topicsOfInterest; }
}
}
public class EntryMapping : ClassMap<Entry>
{
public EntryMapping()
{
Id(entry => entry.Id);
HasMany(entry => entry.TopicsOfInterest)
.Table("TableName")
.AsList()
.Element("ColumnName")
.Cascade.All()
.Access.CamelCaseField();
}
}
I had a similar requirement to map a collection of floats.
I'm using Automapping to generate my entire relational model - you imply that you already have some tables, so this may not apply, unless you choose to switch to an Automapping approach.
Turns out that NHibernate will NOT Automap collections of basic types - you need an override.
See my answer to my own question How do you automap List or float[] with Fluent NHibernate?.
I've provided a lot of sample code - you should be able to substitute "string" for "float", and get it working. Note the gotchas in the explanatory text.