Custom Fill Collection in NHibernate - nhibernate

I'm using NHibernate in my web app and it is mapped with my database. I have a model, somthing like this:
public class Company {
public virtual string Name { get; set; }
public virtual IList<Employee> Employeers { get; set; }
}
public class Employee {
public virtual string Name { get; set; }
public virtual DateTime Birthday { get; set; }
/* other properties */
public virtual Company Company { get; set; }
}
PS: it's not real model but it works for my samples/doubts...
I'm using HQL to get my objects and I'd like to know if is there any way to:
1) Get a Company object and fill the Employeers Colletion with Top 10 Employeers Ordered by Birthday Desc ?
2) Is there any way to, when collection is filled, fill it with only some fields like Name and Birthday? I have a lot of properties that I won't use in my view. I can create a DTO for this but I don't know how to do!
Thanks

Persistent collections and entities represent the current state; they can't have just a part of that (think about it: if they did, how would NH track changes?)
So, in both cases, the answer is queries and DTOs. You can easily retrieve the data you need with HQL:
class EmployeeNameAndBirthDay
{
public string Name { get; set; }
public DateTime Birthday { get; set; }
}
public IList<EmployeeNameAndBirthDay> GetTopEmployees(Company company)
{
return session.CreateQuery(#"
select Name as Name,
Birthday as Birthday
from Employee
where Company = :company
order by Birthday desc
")
.SetParameter("company", company)
.SetMaxResults(10)
.SetResultTransformer(
Transformers.AliasToBean<EmployeeNameAndBirthDay>())
.List<EmployeeNameAndBirthDay>();
}

Related

Automapper - POST / PUT entity nesting hierarchy

I would like to use DTOs and AutoMapper to POST and PUT an entity containing a List of nested entities, having a hierarchy.
Sample :
A company has a list of employees. In this list of employees can have a manager which is also an employee of the same company.
public class Company {
public int Id { get; set; }
public List<Employee> Employees { get; set; }
}
public class Employee {
public int Id { get; set; }
public Company Company { get; set; }
public int CompanyId { get; set; }
public Employee Manager { get; set; }
public int? ManagerId { get; set; }
}
I'd like to create a DTO which is able to POST and UPDATE a Company creating/updating/removing and changing relations between employees.
How would you do knowing that some employees can have no Id yet because they are newly created but are parents of other employees ?
Thanks in advance for the help.
Precision : i use dot net core 2.2, Entity Framework Core and AutoMapper.
You can do this as below.
public class CompanyDto {
public int Id { get; set; }
//Below line cannot exist here, otherwise it will create circular references
//public List<Employee> Employees { get; set; }
}
public class EmployeeDto {
public int Id { get; set; }
public Company Company { get; set; }
public int CompanyId { get; set; }
public Employee Manager { get; set; }
public int? ManagerId { get; set; }
}
After this, you can create your mappings in automapper configuration for Company -> CompanyDto(and reverse map) and Employee to EmployeeDto(and reverse map).
Now, for handling the case of new manager with existing employee, you do either of the following in your repository(with entity objects, not DTO's)
Create a new employee and then update the existing employees with the newly generated employee id in your repository
Or, get all the employees you want to update in your repository(load in context), add the new employee in the context with EntityState.Added. Now, assign the manager of employees you have fetched with the reference of new employee and save your context

How to create mapping relationship using Fluent NHibernate

How can I map one-to-many relationship with
User to Address,
Customer to Address,
Agency to Address and
store in a single Address Table using Fluent NHibernate
public class User
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Customer
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Agency
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Address
{
public virtual int Id { get; set; }
public virtual string Address1 { get; set; }
public virtual string Address2 { get; set; }
public virtual string City { get; set; }
public virtual string State { get; set; }
}
I think you'll need to store your relations independently to connect addresses and users/customers/agencies if you want to be able to use the same address for all types. This involves introducing a new table that only stores ID pairs, and making that the storage location for your relationship.
You can map collections as many-to-many and use the table method to name your link table. Your mapping would look something like:
public UserMap : ClassMap<User> {
Id (u => u.Id);
Map (u => u.Name);
HasManyToMany (u => u.Addresses).Table ("UsersXAddresses");
}
You'll need a similar link table for customers and agencies.
In the constructor for your mapping class, map the link using the HasMany method. HasMany will create a one-to-many relationship. HasManyToMany will create a many-to-many relationship.
For example: HasMany(x => x.Address).LazyLoad();
This will create a one-to-many relationship between the User class and the Address class.
For the many-to-many, you will also need to specify the table name and if you so desire, the left and right side table mappings.
For example: HasManyToMany(x => x.Address).Table("AddressToUser").ParentKeyColumn("AddressId").ChildKeyColumn("UserId").LazyLoad();
If you decide that you want to set up a distinction between a UserAddress and an AgencyAddress (where these are sub-classes of Address) - you can use the DiscriminateSubClassesOnColumn method in the AddressMap class so the FNH knows to create an extra column in order to determine which type of object to create.
For example: DiscriminateSubClassesOnColumn("Type").AlwaysSelectWithValue();
You should be able to use FNH Automapping to map these classes "as is".
It will handle all the relationships in your object model.
I believe it will put all the addresses in a single Address table as you desire, but can't say for sure.

How to use components in fluent nhibernate

I'm working on a legacy MySql database and have the following entities:
public class Company
{
public int Id { get; set;}
public string Address { get; set; }
public string City { get; set; }
}
public class CompanyDepartment
{
public int Id { get; set;}
public string Address { get; set; }
public string City { get; set; }
}
The idea is that a company only use the department class if it has more than one department.
Right now I'm trying to make a company/department search, this means I need a list of all departments and therefore I need to "create" departments of all the companies that only has one department, and therefore don't have a entry in CompaynyDepartment.
To do this I was thinking of use components in fluent NHibernate, but I'm not sure I can join the real departments with the fake ones?
Is there a better approach to this problem? It's not an option to change the database structure.
I ended up changing the database structure

NHibernate - QBE

I have a problem using QBE with NHibernate. I have a one-to-one relationship between a Person class and an Employee.
public class Person
{
public virtual Employee Employee { get; set; }
public virtual int Age { get; set; }
public virtual string Forename { get; set; }
public virtual string Surname { get; set; }
public virtual int PersonID { get; set; }
}
public class Employee
{
public virtual int PersonID { get; set; }
public virtual string PayRollNo { get; set; }
public virtual int Holidays { get; set; }
public virtual Person Person { get; set; }
}
As an example, I want to get all Employees where Employee.Forename="John" and Employee.Person.PayRollNo = "231A". I was wondering if I could use Query By Example to do this?
I have not been able to find a definitive "no" but I haven't been able to get this work. I've found that QBE is promising but unfortunately not very useful due to the following limitations:
Cannot query related objects.
Requires public parameterless constructor.
Initialized properties are included in query unless specifically excluded using ExcludeProeprty. For example, bool properties are restricted to false in the where clause, DateTime as DateTime.MinValue. This makes the query very brittle because class modifications may have bad side effects.

Presentation layer and domain model classes naming conventions

What are the naming conventions you use for application domain model classes and presentation layer classes? Postfixes/Prefixes to distinguish the aim of the class from the first sight:
For example information about the person that is returned from DAL can be
public class PersonEntity
{
public Guid Id { get; set; }
public SexType Sex { get; set; }
public Date Birthdate { get; set; }
public string Name { get; set; }
public string Family { get; set; }
public string Patronymic { get; set; }
...
}
or may be you prefer PersonData or PersonInfo or something more appropriate?
Than I use databinding to create appropriate presentation. For example SexType should be converted to localized string (Male, Mann, Homme, Hombre, ...) Birthdate to appropriate date format (YYYY.MM.DD, DD.MM.YYYY, ...) and full name into -> Family N.P.
So I use another layer of classes for presentation databindings. Something like
public class PersonDecorator
{
public string Sex { get; set; }
public string Date { get; set; }
public string FullName { get; set; }
}
or may it's better to name such class PersonPresenter, or PersonView, or something more appropriate?
Thank you in advance!
The EntityPurpose convention for class names works just fine in a lot of places, especially if you have several entities (Persons, Cars, etc) and several layers (Model, View, Action, etc).
I'd name your class PersonPresentation.