i have one problem (obviously :) )
Is it possible to make dynamic queries in nHibernate in that way...
I have many tables (let we say: User, City, Country, Continet,...) is it possible to flaten this data so i do not need to know joins between this tables (get continent for user, without making join user.city, city.country, coutry.continent)?
The point is i want to some kind flatten data, so user can dynamically select data on user interface without knowing data model behind application?
It will be great that someone gave me at least idea how to make this, or if it's possible...
One example on web is GoogleAnalytics Custom reports (you can drag dimensions and metrics on UI and get results)
You said you're using Fluent NHibernate, which means that, assuming your domain model is structured correctly, you should not need to use any joins.
"Flattening" the data is a UI concern, not a database concern, so you shouldn't flatten your data model or simplify it for the UI unless you absolutely have to.
Let's assume you have the following entities:
public class User
{
public virtual string Name { get; set; }
public virtual City City { get; set; }
}
public class City
{
public virtual string Name { get; set; }
public virtual Country { get; set; }
}
public class Country
{
public virtual string Name { get; set; }
}
If you want to filter users by a certain country, the LINQ query for this (assuming NHibernate 3) would be:
var country = session.Single<Country>(x => x.Name == "Africa");
session.Query<User>().Where(x => x.City.Country == country);
Related
I have an Effort entity and a Schedule entity.
The Schedule entity represents the page on wich Efforts are displayed.
Each Effort can have a separate Order on each Schedule page.
So the best DB structure for this case would look like this
Effort -> ScheduleOrder(with position) <- Schedule
so the one-to-many and many-to-one.
Now I need to sort Efforts on page usig NHibernate criteria.
So I need to use something like property that returns Position for each Schedule.
I can acheave this by using DB View or Property with customised Select query.
Anyone has an idea how to do sorting from one-to-many relationship in a better way?
with
class ScheduleOrder
{
public virtual Effort Effort { get; set; }
public virtual Schedule Schedule { get; set; }
public virtual int Position { get; set; }
}
var efforts = session.CreateCriteria<ScheduleOrder>()
.Add(Expression.Eq("Schedule", schedule))
.AddOrder(Order.Asc("Position"))
.SetFetchMode("Effort", FetchMode.Eager)
.List()
.Select(so => so.Effort);
or with
class Schedule
{
// LIst has a position
public virtual IList<Effort> Efforts { get; set; }
}
HasMany(x => x.Efforts)
.AsList("position");
// or
HasManyToMany(x => x.Efforts)
.AsList("position");
// schedule.Efforts have the right order
my user's table in the database is becoming increasingly larger (in terms of columns not rows) and as a consequence is slowing down various areas of my site. This is because it tries to grab every column from the user's table everytime it does a join against it.
I figured i would keep all the common fields in the user's table and then put the additional fields in seperate tables. For example, say i have the following tables in my database:
Users:
- UserID (PK, Identity)
- UserName
- Password
...
UsersActivity:
- UserID (PK, FK)
- LastActivityDate
- LastLoginDate
...
UsersPreferences:
- UserID (PK, FK)
- HtmlEmail
- HideEmail
...
With the following entities:
public class User {
public virtual int UserID { get; set; }
public virtual string UserName { get; set; }
public virtual string Password { get; set; }
public virtual UserActivity Activity { get; set; }
public virtual UserPreferences Preferences { get; set; }
}
public class UserActivity {
public virtual User User { get; set; }
public virtual DateTime LastActivityDate { get; set; }
public virtual DateTime LastLoginDate { get; set; }
}
public class UserPreferences {
public virtual User User { get; set; }
public virtual bool HtmlEmail { get; set; }
public virtual bool HideEmail { get; set; }
}
I was just wondering what is the best way to map this for optimum performance? I figured i could do a one-to-one mapping on the Activity and Performance properties in the User entity. However as far as i understand one-to-one mapping doesn't support lazy loading and this approach would end up being slower.
I also looked into component mapping and wasn't too sure whether i could map this into a seperate table (please correct me if it would be better to keep it in the same table) and whether components supported lazy loading.
Before i go about doing some heavy refactoring of my application i thought i would get the opinion of someone who might have done this. Really appreciate the help.
Thanks
Edit: I found that you could lazy load a one-to-one relationship as long as it is required/constrained. Which it is my case. Therefore i went ahead and carried out the instructions in the following article:
http://brunoreis.com/tech/fluent-nhibernate-hasone-how-implement-one-to-one-relationship/
The trouble now is that i get the error:
NHibernate.Id.IdentifierGenerationException: NHibernate.Id.IdentifierGenerationException: null id generated for: UserActivity.
In NHibernate 3.0 one-to-one relationship supports lazy loading.
And I think that it is better to use Component with combination of Lazy property. Then you will be able to leave all properties in one table and not load them all at once.
You should do some additional application profiling to determine why you're having a performance problem. It's unlikely that it's due to the number of columns in the select list. You probably have an N+1 select problem.
That said, there are many good reasons to use a lightweight object so you might want to look at implementing a DTO (data transfer object) for this.
I have an Class that is named Show one of the properties "Country" is a reference to another table.
Show Class
public class Show
{
public virtual int ID { get; set; }
public virtual Country CountryOrigin { get; set; }
public virtual string EnglishName { get; set; }
}
Country Class
public class Country
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
}
I have it all mapped and working, but now I am wanting to get more specific results. I have used the criteria api to get all the data and sort it, but now I only want to get shows based on country name. Here is what I thought would work, but apprently doesn't.
public IList<Show> AllShowsByCountry(string countryName)
{
IList<Show> shows;
shows = _session.CreateCriteria(typeof(Show))
.Add(Restrictions.Eq("CountryOrigin.Name", "China" ))
.AddOrder(Order.Asc("EnglishName"))
.List<Show>();
return shows;
}
I was thinking that the first part of the restriction might work similar to HQL and you can use objects.
1) The question I guess is am I mis-understanding how HQL works or criteria or both?
2) Also how would you do this properly using criteria?
Update
Here is the error I am getting
could not resolve property: CountryOrigin.Name of: Entities.Show
For Criteria, use the following:
_session.CreateCriteria<Show>()
.CreateAlias("CountryOrigin", "country")
.Add(Restrictions.Eq("country.Name", countryName))
.AddOrder(Order.Asc("EnglishName"))
.List<Show>();
Of course HQL is easier when you are not constructing a dynamic query (search):
_session.CreateQuery(
#"
from Show
where CountryOrigin.Name = :countryName
order by EnglishName
")
.SetParameter("countryName", countryName)
.List<Show>();
And Linq always rocks:
_session.Query<Show>()
.Where(s => s.CountryOrigin.Name = countryName)
.OrderBy(s => EnglishName)
.ToList();
(.Query is for NH 3.x; for 2.x use .Linq)
I am messing around with NHibernate Search and Lucene to create a searchable index of legal entities. My domain model looks somewhat like this:
[Indexed]
public abstract class LegalEntity : AggregateRoot
{
public virtual Address Address { get; set; }
}
public class Person : LegalEntity
{
public virtual string FirstNames { get; set; }
public virtual string LastName { get; set; }
}
public class Company: LegalEntity
{
public virtual string Name { get; set; }
}
public class Address : Component
{
public virtual string Street { get; set; }
public virtual string HouseNumber { get; set; }
// etc...
}
As the subclassing implies, LegalEntity is an NHibernate entity specialized as Person and Company, and Address is an NHibernate component.
Now, how would I best go about creating a really Google-like fuzzy search that includes all the fields of a LegalEntity, including those inside the Address component?
My first idea was to implement an AddressFieldBridge to help in bringing in the fields of the Address component, and then just throw in [Field] on all the fields, but then I could not find a way to construct a FuzzyQuery as a conjuntion between multiple search terms.
My next idea was to create an abstract property tagged with [Field] on LegalEntity, like so:
[Field(Index.Tokenized)]
public abstract string SearchableText { get; }
and then have Person and Company return texts that combine names and all the fields from the Address component into one string, which would then be tokenized and indexed by Lucene.
That, however, made me feel kind of icky.
I would like to learn the best and least intrusive (from a domain model perspective) way to accomplish this task - any suggestions are appreciated :)
Take a look at my question.
Andrey created patch to specify lucene stuff outside. Syntax ain't uber clean (maybe there's some progress done on this, haven't checked), but i guess it gets job done.
My entities look something like that (simplified):
public class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
public IList<Department> Departments { get; set; }
}
public class Department
{
public Guid Id { get; set; }
public string Name { get; set; }
}
I'm querying the database through criteria api for all persons that have a department with a certain name that should match a like-pattern.
It happens that a person contains two or more departments whose names contain the same character sequence which is used by the query. Therefore the same person is returned multiple times. To surpress this, I know that I can use criteria.SetResultTransformer(Transformers.DistinctRootEntity); but this works only as long as the result is not paged.
When I'm paging the result I don't only need to get the first page but I also need to know how many entities there are in total. Unfortunately the result transformer does not work when calling criteria.SetProjection(Projections.RowCount()) as there is no result to be transformed.
Can I somehow avoid retrieving the whole list of person with the result transformer and then manually taking the right part out of the collection?
Best Regards
Oliver Hanappi
You need to include distinct in your sql request. Some information you can find here. Second answer mostly