How to use look up values with NHibernate? - nhibernate

How do you handle look up values with NHibernate? For example, I have an Order entity and it has a BillingAddress property that is a value object named Address, it's simple if the Address object just contains State and Country properties as strings. But what if I want a Country contains a list of its states the Order form can populate appropriate state dropdown list for each selected country.
Can I still create Country and State as value objects? Or they must be entities? And if they are entities, can Address be a value object?
Below is a sample code of my example:
public class Order
{
public virtual int OrderId { get; set; }
public virtual Address BillingAddress { get; set; }
}
public class Address
{
public virtual State State { get; set; }
public virtual Country Country { get; set; }
}
public class Country
{
public virtual string Name { get; set; }
public virtual ICollection<State> States { get; set; }
}
public class State
{
public virtual string Name { get; set; }
public virtual Country Country { get; set; }
}

If you want to store the lookup data in the database, then they need to be entities. Otherwise, it is up to you. If you do, I suggest marking them as immutable and putting them in a read only 2nd-layer cache.
If you store them as values, and they have multiple fields like Abbrevation, Name, Coordinates, etc. then you can save the id as a value in the data store, and have the lookup data hard-coded as a plain C# class. You'll just retrieve the id value from NHibernate, and then your calling code will have to run the lookup methods on the class. Not as elegant, but simplifies from the NHibernate/database perspective.
Either method is acceptable--it more depends on how you plan on using them: who is maintaining and using the code at each level, where you want the caching and/or lookup code, if you control the calling code or not, etc.

Related

Confused about DTOs when reading and editing. How to desing DTO for filling the form in VUEjs app?

I am trying to develop an enterprise-level application. I have domain and application services. I have created my DTOs for multiple purposes separately. But confused about which way I should use them from the API viewpoint.
I have complex objects lets say,
public class Entity{
public int Id { get; set; }
public string Name { get; set; }
public int? ManufacturerId { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
}
public class Manufacturer{
public int Id { get; set; }
public string Text { get; set; }
}
And I have corresponding DTOs designed with composition now. It was separated before.
public class EntityBaseDto{
public string Name { get; set; }
}
public class EntityReadDto : EntityBaseDto{
public string Manufacturer { get; set; }
}
public class EntityWriteDto : EntityBaseDto{
public int? ManufacturerId { get; set; }
}
Now the question is,
I have a table which is filled with List<EntityReadDto> which is clear. Before, EntityReadDto also had the ManufacturerDto as fully included with id and text. Whenever I require to edit one of the entries from the table I was able to load the dropdown selected items or list of tags etc with the ids attached to the Manufacturer objects within ReadDtos. Now it is not possible. Since I wanted to simplify the codes I just converted them to strings that are read-only. Now I have created another endpoint to get an editable version of the record when needed. Ex: EntityWriteDto will be used to fill the form when the edit is clicked on a specific item. The manipulation will be carried on that DTO and sent with the PUT type request to edit the record.
I am not sure if this approach is ok for these cases. What is the best practice for this? I have many objects related to the entities from other tables. Is it ok to make a call to get an editable version from the backend or need to have it right away in a VUEjs app?

Entity Framework Core Code First Model Navidation Properties

I have a Web API that uses entity framework. I have several tables there were created using the code first setup. My Competitions class is defined below.
Everything works great and I'm able to get my Competitions table data along with all the data in the navigation properties that are returning a collection. However, I'm not able to get any values for the CompetitionTypes and Users navigation properties. OwnerId references UserId in the Users table.
How would I get the linked data in my CompetitionTypes and Users table? I basically want the same thing as the three collection navigation properties, except that CompetitionTypes and Users would only return one row.
public partial class Competitions
{
[Key, Required]
public int CompetitionId { get; set; }
public int CompetitionTypeId { get; set; }
public int OwnerId { get; set; }
public string CompetitionName { get; set; }
public CompetitionTypes CompetitionTypeId { get; set; }
public Users UserId { get; set; }
public ICollection<Participants> Participants { get; set; }
public ICollection<ResultStats> ResultStats { get; set; }
public ICollection<Results> Results { get; set; }
}
}
EF auto-matches FK properties with navigation properties based on conventions. Namely, it expects FK properties to be named the same as navigation properties, just with Id at the end. In other words, for it to automatically match up OwnerId, you'd need a navigation property like:
public User Owner { get; set; }
Since your navigation property is UserId, it's actually looking for a property named UserIdId.
If you don't want to follow conventions, then you must either use the ForeignKey attribute or fluent config to tell EF which property belongs with which.
That said, there's some pretty major issues with your naming of things here. First, entities should always be singular User, not Users. Second, you should not have navigation properties that end with Id: e.g., User, not UserId. Only actual PK or FK properties should end with with Id. Finally, don't prefix properties on your entity with the entity name. This last one is mostly for readability. Which is more natural: competition.Id or competition.CompetitionId? Likewise with CompetitionName; it should just be Name. And, for what it's worth, you don't need Required for either a primary key or a non-nullable type (such as int). In either case, the property is required by default.

Why do I need to name the properties in my index with underscore?

Given that I have the following structure (unnecessary details stripped out)
public class Product {
public Guid Id { get; set; }
public string Name { get; set; }
public Manufacturer Manufacturer { get; set; }
}
public class Manufacturer {
public Guid Id { get; set; }
public string Name { get; set; }
}
If I have a lot of these kind of products stored in raven and I want to index them by manufacturer id (or maybe some other things as well) I'd make an index such as this (of course in real life this index also contains some other information as well...)
public class ProductManufacturerIndex : AbstractIndexCreationTask<Product> {
public ProductManufacturerIndex() {
Map = products => from product in products
select new {
Manufacturer_Id = product.Manufacturer.Id,
};
}
}
My question here is, why do I need to name my field Manufacturer_Id? If I do not name it Manufacturer_Id I get exceptions when attempting to query my index since the manufacturer id column is not indexed.
Basically, why can't I do this? (Which would be my first guess)
public class ProductManufacturerIndex : AbstractIndexCreationTask<Product> {
public ProductManufacturerIndex() {
Map = products => from product in products
select new {
product.Manufacturer.Id,
};
}
}
There is a naming convention that RavenDB uses. If you aren't naming your fields properly, it doesn't know how to map things.
In this case, the second index you use has a property of Id, but RavenDB has no way of knowing that you mapped the Manufacturer's id, and not the root id.
That is why we have this convention. You can change it if you really want to, but it is generally not recommended.

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

Custom Fill Collection in 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>();
}