I have the following model which I have created and mapped with nHibernate.
Using lazy loading so I don't need to get the Vehicles for the Dealer at the start.
Public class Dealer
{
public virtual string Name { get;set;}
public virtual IList<Vehicles> Vehicles { get;set;}
}
Now let's assume the Dealer has thousands of vehicles.
If I do Dealer.Vehicles.Count then NH will select and pull all the data.
What is the best way to simply get a count? Is there any way in which I can get a count with out declaring A new property dealerCount within the Dealer Class?
Also there is a feature in Hibernate which I believe will be implemented in a newer version of NH called Extra Lazy Loading. Would this solve the problem?
extra lazy loading would issue sql instead of populating the collection for certain operations such as Count or Contains. In fluent mappings its used as:
HasMany(x => x.CollectionProperty).ExtraLazyLoad();
or HBM
<one-to-many lazy="extra" ...
It's only usefull if you have large collections and need the special behavior.
Use count projection (Projections.RowCount)
Related
I am looking for some way to dynamically map database tables classes in my application using nhibernate (or if some other ORM works then let me know). I am fairly new to nhibernate, I used entity frameworks in the past though.
Most of my application will be using a static structures and fluent nhibernate to map them.
However there are multiple database tables that will be needed to be created and mapped to objects at each install site. These will all have as a base structure (id,name etc) however they will have additional fields depending on the type of data they are capturing. From some reading I found that I can use the "dynamic-component" mapping in xml to add fields using an IDictionary Attributes property. This is the first step and seems relatively straight forward. Ref (http://ayende.com/blog/3942/nhibernate-mapping-dynamic-component)
The second step is where I am struggling. I will need to define tables and map them depending on the client’s need. As stated above each of the tables will have a set of static properties, and some dynamic ones. They will also need to reference a static “Location”Class as shown below
Location (STATIC) (id,coordinates)
-----DynamicTable1 (DYNAMIC) (id,Name,location_id, DynamicAttribute1, DynamicAttribute2........)
-----DynamicTable2 (DYNAMIC) (id,Name,location_id, DynamicAttributeA, DynamicAttributeB....)
We will need to be able to create / map as many of these DynamicTables as the client needs. DynamicTable1, DynamicTable2 etc will most likely be different in some ways for most client sites. Is there any way in nhibernate to achieve this? The creating / management of the tables in the Database will be managed elsewhere, I just need some way to get this to map in my ORM.
A bit of background
This application will be used to store geological data. As geological data is inherently different depending on where it is, and geologist are using different methods and looking for different elements (gold, coal etc), the data structure to store this information needs to be extremely flexible.
Take a look at the new Mapping By Code functionality of NH 3.2. It should make it easy to create new table definitions at runtime. In contrast to Fluent, you don't need to write a mapping class, you just can add new classes in for loops:
// lookup all dynamic tables in the database using SQL or SMO or whatever
var dynamicTables = GetDynamicTables();
// map all dynamic tables
foreach(var table in dynamicTables)
{
mapper.Class<MyGenericEntity>(ca =>
{
// use an entity name to distinguish the mappings.
ca.EntityName(table.Name);
ca.Id(x => x.Id, map =>
{
map.Column("Id");
map.Generator(Generators.HighLow, gmap => gmap.Params(new { max_low = 100 }));
});
// map properties, using what ever is required: if's, for's ...
ca.Property(x => x.Something, map => map.Length(150));
});
}
Using the entity name you can store and load the entities to and from different tables, even if they are mapped as the same entity class. It is like Duck Typing With NHibernate..
Believe me, it won't be easy. If you are interested in a big challenge which impresses every NH expert, just go for it. If you just want to get it working you should choose a more classic way: create a static database model which is able to store dynamic data in a generic way (say: name value pairs).
see answer in Using nNHibernate with Emitted Code
class DynamicClass
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Location Location { get; set; }
public virtual IDictionary DynamicData { get; set; }
}
Template
<hibernate-mapping>
<class name="DynamicClass">
...
<dynamic-component name="DynamicData">
<!--placeholder -->
</dynamic-component>
</class>
</hibernate-mapping>
replace <!--placeholder --> with generated
<property
name="P1"
type="int" />
<property
name="P2"
type="string" />
configure Sessionfactory
var sessionFactory = new NHibernate.Cfg.Configuration()
.AddXml(generatedXml)
... // DatabaseIntegration and other mappings
.BuildSessionFactory();
Query
var query = session.CreateCriteria<DynamicClass>();
foreach (var restriction in restrictions)
{
query.Add(Restrictions.Eq(restriction.Name, restriction.Value))
}
var objects = query.List<DynamicClass>();
Edit: ups i havent realised you need multiple tables per client
Option 1:
<class name="DynamicClass" table="tablenameplaceholder"> with replace and a different Sessionfactory for each dynamic class
Option 2:
Subclassing the dynamic class and use TPS (table per subclass) mappings
Option 3: see Stefans answer just with xml
<class name="DynamicTable1" class="DynamicClass" table="DynamicTable1">
I'm just trying to get my head around nHibernate and have a query. When setting up the mappings file (with Fluent or regular .hbm.xml files) you specify relationships (bags; one-to-many, etc) and sub-types - the idea being (I believe) is that when you fetch an object it also fetches and matching data. My question is can I programmatically tell my query to ignore that relationship?
So, below, there is a Foo class with a list of Bar objects. Within the mappings file this would be a one-to-many relationship and sometimes I want to retrieve a Foo with all Bars BUT sometimes I want to just retrieve the Foo object without the Bar, for performance reasons. How can I do this?
public class Foo { public int Id { get; set; } public List<Bar> { get; set; } }
public class Bar { public int Id { get; set; }
Cheers
The relationship shouldn't be loaded automatically unless you turn off Lazy Loading or specify it to be eager loaded in the query.
Edit:
To answer your questions in the comment below.
1) It's done as part of the query. An basic example using QueryOver in NHibernate 3.0 would look something like:
var result = Session.QueryOver()
.Fetch(x => x.Category).Eager
.Where(x => x.Price > 10)
.List();
I think with ICriteria it's "SetFetchMode("Category", FetchMode.Eager)"
2) If you turn off lazy-loading on the mapping for an object, it will effectively always be eager loaded. Tho I suggest you eager load on a query-by-query basis to avoid the possibility of having a massive chain of data loaded, or loading data you don't actually need.
I have this scenario:
class A
{
public virtual int Id { get; set; }
public virtual B Child { get; set; }
}
class B
{
public virtual int Id { get; set; }
}
In the mapping of class A, I have a reference to class B:
map.Reference(a => a.Child).LazyLoad();
Now when I do something like:
Session.Query<TypeOfA>().Select(a => a);
Apart from the normal select * from ATable I get n selects from the BTable for each A line. Is like lazy loading is not working.
My questions are:
How to I make the lazyload work here ?
Can I bring the A entities and B entities in a single query ?
Thank you,
Lazy loading is switched on by default and should actually work. If there would be a problem, for instance if it can't generate the proxy for class B, it would complain when creating the session factory.
Are you sure that the queries for B are done by the query itself, and not be subsequent access to A?
You could optimize the access to B in two ways: fetch them together with A in a single query. (I don't know fluent, this is the xml way to configure it:)
<many-to-one fetch="join" ...>
This has some problems when used with lists and could also blow up your query a lot. It is of course not lazy loading at all.
Another, very nice and powerful optimization is batch fetching. It allows the instances to be fetched in separate queries, but fetches several of them at once.
<class name="B" batch-size="20" ...>
This would fetch 20 B's at once in one query. It is also available for lists:
<one-to-many fetch-size="20" ...>
Expanding on Stafan's suggestion to use batch-size, a quick Google search reveals that Fluent NHibernate now supports BatchSize for queries. From the docs:
ClassMap<T> BatchSize(int size)
Sets the query batch size for this entity.
Never used it myself, and the documentation is minimal (like a lot of FNH), but maybe you can find some sample code.
I have the following entity
public class Employee
{
public virtual int Id {get;set;}
public virtual ISet<Hour> XboxBreakHours{get;set}
public virtual ISet<Hour> CoffeeBreakHours {get;set}
}
public class Hour
{
public DateTime Time {get;set;}
}
(What I want to do here is store information that employee A plays Xbox everyday let's say at 9:00 13:30 and has a coffee break everyday at 7:00 12:30 18:00) - I am not sure if my approach is valid at all here.
The question is how should my (ideally fluent) mappings look like here? It is not necessary (from my point of view) for Hour class to have Id or be accessible from some kind of repository.
Depending on how you want to do it, you either need to map your collection as an element mapping or as a component collection (that's <element> and <composite-element> in NHibernate terms). The former will need an IUserType defining, while the latter is for if you're going to have your Hour class have more than one property.
If you're sticking with a single property, you'll need to define an IUserType so NHibernate knows how to translate to and from your type to your database. Once you've done that, you can map it with Fluent NHibernate like so:
HasMany(x => x.XboxBreakHours)
.Element("value", x => x.CustomType<YourUserType>);
That specifies that your collection is stored in a table with a column called value containing the actual values. The CustomType call is what tells NHibernate to use the IUserType for this collection.
If you're going to have multiple properties in your Hour class, then you need to do the following (note: this is actually very similar to doing a Component mapping).
HasMany(x => x.XboxBreakHours)
.Component(comp =>
{
comp.Map(x => x.Time);
comp.Map(x => x.Another);
});
Does anybody know how I would map an entity with two many-to-many collections of the same child type.
My database structure is this....
The "normal" relationship will be....
tbl_Parent
col_Parent_ID
tbl_Parent_Child_Xref
col_Parent_ID
col_Child_ID
tbl_Child
col_Child_ID
The alternative relationship is...
tbl_Parent
col_Parent_ID
tbl_Include_ParentChild_Xref
col_Parent_ID
col_Child_ID
tbl_Child
col_Child_ID
The entity and mapping look like this...
public partial class ParentEntity : AuditableDataEntity<ParentEntity>
{
public virtual IList<ChildEntity> Children { get; set; }
public virtual IList<ChildEntity> IncludedChildren { get; set; }
}
public partial class ParentMap : IAutoMappingOverride<ParentEntity>
{
public void Override(AutoMapping<ParentEntity> mapping)
{
mapping.Table("tbl_Parent");
mapping.HasManyToMany(x => x.Children)
.Table("tbl_Parent_Child_Xref")
.ParentKeyColumn("col_Parent_ID")
.ChildKeyColumn("col_Child_ID")
.Inverse()
.Cascade.All();
mapping.HasManyToMany(x => x.IncludedChildren)
.Table("tbl_Include_ParentChild_Xref")
.ParentKeyColumn("col_Parent_ID")
.ChildKeyColumn("col_Child_ID")
.Inverse()
.Cascade.All();
}
}
The error that I'm getting is
"System.NotSupportedException: Can't figure out what the other side of the many-to-many property 'Children' should be."
I'm using NHibernate 2.1.2, FluentNhibernate 1.0.
It seems FNH is confused because you seem to map the same object (ChildEntity) to two different tables, if I'm not mistaken.
If you don't really need the two lists to get separated, perhaps using a discriminating value for each of your lists would solve the problem. Your first ChildEntity list would bind to the discriminationg value A, and you sesond to the discriminating value B, for instance.
Otherwise, I would perhaps opt for a derived class of your ChildEntity, just not to have the same name of ChildEntity.
IList<ChildEntity> ChildEntities
IList<IncludedChildEntity> IncludedChildEntities
And both your objects classes would be identitical.
If you say it works with NH, then it might be a bug as already stated. However, you may mix both XML mappings and AutoMapping with FNH. So, if it does work in NH, this would perhaps be my preference. But think this workaround should do it.
You know I'm just shooting in the dark here, but it almost sounds like your ChildEntity class isn't known by Hibernate .. that's typically where I've seen that sort of message. Hibernate inspects your class and sees this referenced class (ChildEntity in this case) that id doesn't know about.
Maybe you've moved on and found the issue at this point, but thought I'd see anyway.
Fluent is confused because you are referencing the same parent column twice. That is a no-no. And as far as I can tell from the activity i have seen, a fix is not coming any time soon.
You would have to write some custom extensions to get that working, if it is possible.
To my great pity, NHibernate cannot do that. Consider using another ORM.