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

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;
}

Related

remove from collection without load all collection data. confused which collection mapping to use

I have a many-to-many relationship between Assignment and User
When trying to delete an user from an assignment, I see all users are loaded in the collection.
How to I avoid that?
public class User
{
public virtual int Id { get; private set; }
public virtual IList<Assignment> Assignments { get; set; }
}
public class Assignment
{
public virtual int Id { get; private set; }
public virtual ICollection<User> Users { get; set; }
}
Mappings:
HasManyToMany(user => user.Assignments).Table("UserToAssignment").ParentKeyColumn("UserId").ChildKeyColumn("AssignmentId").Inverse().ExtraLazyLoad();
HasManyToMany(productAssignment => productAssignment.Users).AsSet().Table("UserToAssignment").ParentKeyColumn("AssignmentId").ChildKeyColumn("UserId").LazyLoad();
Calling code:
assignment.Users.Remove(user)
Initially I used Bag instead of Set for Assignment mapping, but when updating it, it was deleting and then reinserting alot of rows in the AssignmentsToUsers table. So I changed to using Set.
But now I see a problem with using Set: it brings all data in memory.
What is the recommended way of doing this?
You can't avoid this and I would ignore it if performance is acceptable. If performance is a problem, there are three ways I can think of to tackle it:
If the other side of the collection (User.Assignments) is lighter weight then remove the assignment from the user instead.
Model the many-to-many table and delete the object directly. You would have to be certain that the Users collection is not going to be loaded prior to this because the in-memory representation will still contain the deleted record.
Direct delete using SQL -- this has the same caveat as #2.
You should use extra lazy mode also for Assignment.Users.

Is there something analogous on NHibernate regarding Entity Framework's navigation property?

Is there something analogous on NHibernate regarding Entity Framework's navigation property? For example, instead of:
s.Save(new Product { Category = s.Get<Category>("FD"), Name = "Pizza" });
I wish I could write:
s.Save(new Product { CategoryId = "FD", Name = "Pizza" });
Can I inform NHibernate not to use the Product's Category property as a mechanism to save the Product's category? I want to use CategoryId instead(Read: I don't want to use DTO). Entity Framework seems able to facilitate avoiding DTO patterns altogether, while at the same time offering the full benefit of ORM(can avoid joins using navigation properties). I want the EF's offering the best of both worlds(lean mechanism for saving objects, i.e. no need to retrieve the property's object) and navigation mechanism for querying stuff
Sample from EF: http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-code-first-walkthrough.aspx
public class Category
{
public virtual string CategoryId { get; set; }
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
}
public class Product
{
public virtual int ProductId { get; set; }
public virtual string Name { get; set; }
public virtual string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
[UPDATE]
Regarding James answer, I tried seeing the NHibernate's actions in SQL Server Profiler.
// this act didn't hit the Category table from the database
var c = s.Load<Category>("FD");
// neither this hit the Category table from the database
var px = new Product { Category = c, Name = "Pizza" };
// this too, neither hit the Category table from the database
s.Save(px);
Only when you actually access the Category object that NHibernate will hit the database
Console.WriteLine("{0} {1}", c.CategoryId, c.Name);
If I understand your question, you want to save a Product with a Category without hitting the database to load the Category object. NHibernate absolutely supports this and you almost have the right code. Here is how you do it in NHibernate:
s.Save(new Product { Category = s.Load<Category>("FD"), Name = "Pizza" });
This will not hit the database to fetch the actual Category, but it will simply save a Product with the correct Category.Id. Note that you don't need (and I would recommend getting rid of Product.CategoryId).
Now why does this work with session.Load(), but not session.Get()... With session.Get(), NHibernate has to return the object or null. In .NET, there is no way for an object to replace itself with null after the fact. So NHibernate is forced to go to the database (or L1 cache) to verify that the "FD" Category actually exists. If it exists, it returns an object. If not, it must return null.
Let's look at session.Load(). If the object is not present in the database, it throws an exception. So NHibernate can return a proxy object from session.Load() and delay actually hitting the database. When you actually access the object, NHibernate will check the database and can throw an exception at that point if the object doesn't exist. In this case, we're saving a Product to the database. All NHibernate needs is the Category's PK, which it has in the proxy. So it doesn't have to query the database for the Category object. NHibernate never actually needs to hydrate an actual Category object to satisfy the save request.

Fluent NHibernate: How to create one-to-one bidirectional mapping?

I had a similar question to Fluent NHibernate: How to create one-to-many bidirectional mapping? but I was interested in the situation when I have a one-to-one mapping. For instance
Umbrealla
ID
Owner
UmbreallaOwner
ID
Umbrella
As we know each umbrella can only be owned by one person and nobody owns more than one umbrella. In a fluent map I would have something like
UmbrellaMap()
{
Id(x=>x.ID);
References<UmbrellaOwner>(x=>x.Owner);
}
UmbrellaOwnerMap()
{
Id(x=>x.ID);
References<Umbrella>(x=>x.Umbrella);
}
When creating the tables fluent will create a field in umbrella referncing the ID of umbrellaOwner and a field in umbrellaOwner referencing umbrella. Is there any way to change the mapping such that only one foreign key will be created but the Umbrella property and the Owner property will both exist? The examples I have seen involve setting the relations up in both directions so adding a new Umbrella looks like
AddUmbrealla(UmbrellaOwner owner)
{
var brolly = new Umbrella();
brolly.Owner = owner;
owner.Umbrella = brolly;
session.Save(owner); //assume cascade
}
which seems logical but a bit cumbersome.
Well, a reference is a reference; one object has a reference to the other. The reverse is not necessarily true.
In your case, you MIGHT get away with a HasOne relationship. However, HasOne is normally for denormalized data. Say you wanted more info about the owner, but you could not change Owner's schema because other code depended on it. You'd create an AdditionalOwnerInfo object, and create a table in the schema in which the OwnerID field of the table was a foreign key to Owner, and also the primary key of the table.
Ayende recommends a two-sided References() relationship in 99.9% of one-to-one cases, where the second object is conceptually separate from the first, but there is an implicit "I alone own exactly one thing" type of relationship. You can enforce the "one and one only" nature of the reference using a Unique().Not.Nullable() modifier set on the References mapping.
To streamline the referential setup, consider defining one object (UmbrellaOwner) as the "parent" and the other (Umbrella) as the "child", and in the parent's property setter, set the child's parent to the current reference:
public class Umbrella
{
public virtual string ID { get; set; }
public virtual Owner Owner { get; set; }
}
public class UmbrellaOwner
{
public virtual string ID { get; set; }
private Umbrella umbrella;
public virtual Umbrella Umbrella
{
get{
return umbrella;
}
set{
umbrella = value;
if(umbrella != null) umbrella.Owner = this;
}
}
}
Now, when you assign the child to the parent, the backreference is automagically set up:
var owner = new UmbrellaOwner{Umbrella = new Umbrella()};
Assert.AreEqual(owner, owner.Umbrella.Owner); //true;

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

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.