NHibernate select specific column - nhibernate

public class Company_Product
{
public virtual Int32 Id { get; set; }
public virtual DateTime SalesDate { get; set; }
public virtual Company Company{ get; set; }
public virtual Product Product { get; set; }
}
public class Company
{
public virtual Int32 Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Company_Product> company_product { get; set; }
}
public class Product
{
public virtual Int32 Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Company_Product> company_product { get; set; }
}
Company.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="BusinessObjectApp"
namespace="BusinessObjectApp.Modal">
<!-- more mapping info here -->
<class name="Company" table="[Company]">
<id name="Id" column="Id">
<generator class="native" />
</id>
<property name="Name" column="Name" />
<bag name="company_product" table="[Company_Product]" inverse="true" lazy="true">
<key column="CompanyID" />
<one-to-many class="Company_Product" />
</bag>
</class>
</hibernate-mapping>
Company_Product.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="BusinessObjectApp"
namespace="BusinessObjectApp.Modal">
<!-- more mapping info here -->
<class name="Company_Product" table="[Company_Product]">
<id name="Id" column="Id">
<generator class="native" />
</id>
<property name="SalesDate" column="SalesDate" />
<!-- Many to many -->
<many-to-one class="Company" name="Company" column="CompanyID" />
<many-to-one class="Product" name="Product" column="ProductID" />
</class>
</hibernate-mapping>
Product.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="BusinessObjectApp"
namespace="BusinessObjectApp.Modal">
<!-- more mapping info here -->
<class name="Product" table="[Product]">
<id name="Id" column="Id">
<generator class="native" />
</id>
<property name="Name" column="Name" />
<bag name="company_product" table="[Company_Product]" inverse="true" lazy="true">
<key column="ProductID" />
<one-to-many class="Company_Product" />
</bag>
</class>
</hibernate-mapping>
I able to retrieve all item if using the code below:
IList<Company_Product> test = session.QueryOver<Company_Product>()
.List<Company_Product>();
However the code below produce error. I know that is because Company_Product class does not have the properties. I want to map them to the corresponding object like the output above. Is it possible?
string query = "SELECT C.Name, P.Name, CP.SalesDate FROM [Company_Product] CP " +
"LEFT JOIN [Company] C ON CP.CompanyID = C.Id " +
"LEFT JOIN [Product] P ON CP.ProductID = P.Id";
var test = session.CreateSQLQuery(query)
.SetResultTransformer(Transformers.AliasToBean<Company_Product>())
.List<Company_Product>();
UPDATE:
Now I able to retrieve the whole object.
Company_Product company_product = null;
Company company = null;
Product product = null;
IList<Company_Product> test = session.QueryOver<Company_Product>()
.Left.JoinAlias(cp => cp.Company, () => company)
.Left.JoinAlias(cp => cp.Product, () => product)
.SelectList(list => list
.Select(cp => cp.Company).WithAlias(() => company_product.Company)
.Select(cp => cp.Product).WithAlias(() => company_product.Product)
.Select(cp => cp.SalesDate).WithAlias(() => company_product.SalesDate)
)
.TransformUsing(Transformers.AliasToBean<Company_Product>())
.List<Company_Product>();
But I cannot set the nested property.
Company_Product company_product = null;
Company company = null;
Product product = null;
IList<Company_Product> test = session.QueryOver<Company_Product>()
.Left.JoinAlias(cp => cp.Company, () => company)
.Left.JoinAlias(cp => cp.Product, () => product)
.SelectList(list => list
.Select(cp => cp.Company.Name).WithAlias(() => company_product.Company.Name)
.Select(cp => cp.Product.Name).WithAlias(() => company_product.Product.Name)
.Select(cp => cp.SalesDate).WithAlias(() => company_product.SalesDate)
)
.TransformUsing(Transformers.AliasToBean<Company_Product>())
.List<Company_Product>();
Can anyone help me? I am new to Nhibernate and sorry for my bad English.

You do not need to use a native SQL query to achieve this.
You can use QueryOver but will have to use projections.
session.QueryOver<Company_Product>()
.JoinQueryOver<Company>(cp => cp.Company, ()=>companyAlias)
.JoinQueryOver<Product>(cp => cp.Product, ()=>productAlias)
.SelectList( l => l.Select( cp => companyAlias.Name)
.Select( cp => productAlias.Name)
.Select( cp => cp.SalesDate));
I haven't tested it, and it's been more than over a year since I've used NHibernate, but it should point you in the right direction. :)
Also, why are you using a bag ? I think a set might be more appropriate.

Related

NHibernate JoinQueryOver on linkin Property in the other class

To put it simple I have these 3 classes
class Bag { int Id; }
class Candy { int Id; }
class CandyBag
{
int Id;
Candy candy;
Bag bag;
}
I need to list all Bags that contains certain type of Candy, Im THINK it goes something like this:
session.QueryOver<Bag>(() => bagAlias)
.JoinQueryOver<CandyBag>()
.Where(candyBag => candgyBag.Bag.Id == bagAlias.Id)
.And(candyBag => candgBag.Candy.Id == userSelectedCandy.Id)
.List();
The thing is, I can't have a property of CandyBag nor Candy in the Bag class, because I have more items that a bag can hold (like Cloth/ClotheBag Food/FoodBag). And I'm saying this because I can't do
session.QueryOver<Bag>(() => bagAlias)
.JoinQueryOver<CandyBag>(bag => bag.CandyBag, () => candyBagAlias)
.Where(candyBag => candyBag.Bag.Id == bagAlias.Id)
.List();
Thanks in advance.
Based on your example I've created this classes:
public class Bag {
public int Id {get; set;}
}
public class Candy {
public int Id { get; set; }
}
public class CandyBag
{
public int Id { get; set; }
public Candy Candy { get; set; }
public Bag Bag { get; set; }
}
and this NHibernate mappings
<class name="Bag" table="Bag" lazy="false" >
<id name="Id">
<generator class="identity" />
</id>
<!--<property name="CreationDate" />-->
</class>
<class name="Candy" table="Candy" lazy="false" >
<id name="Id">
<generator class="identity" />
</id>
<!--<property name="CreationDate" />-->
</class>
<class name="CandyBag" table="CandyBag" lazy="false" >
<id name="Id">
<generator class="identity" />
</id>
<many-to-one name="Candy" column="CandyId" lazy="false" />
<many-to-one name="Bag" column="BagId" lazy="false" />
</class>
To obtain Bag collection of a certain Candy:
IList<Bag> bags = null;
using (var session = OpenSession())
{
CandyBag candyBagAlias = null;
bags = session.QueryOver<CandyBag>(() => candyBagAlias)
.Where(() => candyBagAlias.Candy.Id == userSelectedCandyId )
.List()
.Select(cb => cb.Bag).ToList();
// or with LINQ
bags = (
from bag in session.Query<Bag>()
join candyBag in session.Query<CandyBag>() on bag equals candyBag.Bag
where candyBag.Candy.Id == userSelectedCandyId
select bag
).ToList();
}
return bags;
I prefer the LINQ way because it is really simple to understand.

Nhibernate composite key question

I have a table called person_skills like so:
person_id, skill_type_id, base_score, misc_score
There is a lookup table that contains id, name for skill_types.
Now the tricky thing is that I have a composite key for person_id, skill_type_id. There will be many entries within this table as a person may have 5 skills.
Currently I have got a class like so:
public class skill
{
int BaseScore {get;set;}
int MiscScore {get;set;}
}
Then I have a class to contain all this like below:
public class person_skills
{
int person_id {get;set;}
IDictionary<skill_type, skill> skills {get;set;}
}
Now im not sure if this is the best way to handle this relationship, ultimately I need to be able to give people a link to skills, there is one person to many skills.
I was thinking about just putting in an auto incrememnt id column and use that as the PK, but it doesn't seem ideal. I can change the models and the DB if required, but as this is used within an ajax part of a page I need to be able to change the skills and then update them into the database.
I did not find an actual question but I'll answer anyway. :)
You do not need a surrogate key for the person_skills table. Your composite key, consisting of person_id and skill_type_id, should be sufficient. I believe the following classes and mappings reflect what you are trying to accomplish here.
Classes:
public class Person
{
public virtual int PersonId { get; set; }
public virtual String Name { get; set; }
public virtual IList<PersonSkills> Skills { get; set; }
}
public class SkillType
{
public virtual int SkillTypeId { get; set; }
public virtual String SkillName { get; set; }
public virtual IList<PersonSkills> Persons { get; set; }
}
public class PersonSkills
{
public virtual int PersonId { get; set; }
public virtual int SkillTypeId { get; set; }
public virtual int BaseScore { get; set; }
public virtual int MiscScore { get; set; }
public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj == null || !(obj is PersonSkills))
{
return false;
}
PersonSkills o = obj as PersonSkills;
return (this.PersonId == o.PersonId
&& this.SkillTypeId == o.SkillTypeId);
}
public override int GetHashCode()
{
int hash = 13;
hash = hash + this.PersonId.GetHashCode();
hash = hash + this.SkillTypeId.GetHashCode();
return hash;
}
}
Mappings: (FluentNhibernate)
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Id(x => x.PersonId);
Map(x => x.Name);
HasMany(x => x.Skills)
.KeyColumn("PersonId")
.Cascade.All();
}
}
public class SkillTypeMap : ClassMap<SkillType>
{
public SkillTypeMap()
{
Id(x => x.SkillTypeId);
Map(x => x.SkillName);
HasMany(x => x.Persons)
.KeyColumn("SkillTypeId")
.Cascade.All();
}
}
public class PersonSkillsMap : ClassMap<PersonSkills>
{
public PersonSkillsMap()
{
CompositeId()
.KeyProperty(x => x.PersonId)
.KeyProperty(x => x.SkillTypeId);
Map(x => x.BaseScore);
Map(x => x.MiscScore);
}
}
Mappings (hbm, generated by FluentNHibernate - I removed output that is not required):
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" >
<class xmlns="urn:nhibernate-mapping-2.2" name="Person" table="Person">
<id name="PersonId" type="int">
<column name="PersonId" />
<generator class="identity" />
</id>
<bag cascade="all" name="Skills" mutable="true">
<key>
<column name="PersonId" />
</key>
<one-to-many class="PersonSkills" />
</bag>
<property name="Name" type="String">
<column name="Name" />
</property>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" >
<class xmlns="urn:nhibernate-mapping-2.2" name="SkillType" table="SkillType">
<id name="SkillTypeId" type="int">
<column name="SkillTypeId" />
<generator class="identity" />
</id>
<bag cascade="all" name="Persons">
<key>
<column name="SkillTypeId" />
</key>
<one-to-many class="PersonSkills" />
</bag>
<property name="SkillName" type="String">
<column name="SkillName" />
</property>
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" >
<class xmlns="urn:nhibernate-mapping-2.2" name="PersonSkills" table="PersonSkills">
<composite-id mapped="false" unsaved-value="undefined">
<key-property name="PersonId" type="int">
<column name="PersonId" />
</key-property>
<key-property name="SkillTypeId" type="int">
<column name="SkillTypeId" />
</key-property>
</composite-id>
<property name="BaseScore" type="int">
<column name="BaseScore" />
</property>
<property name="MiscScore" type="int">
<column name="MiscScore" />
</property>
</class>
</hibernate-mapping>

Is it possible to use an NHibernate type discriminator as part of a foreign key

Taking the following object model:
public abstract class Entity
{
public Guid Id { get; set; }
}
public class Category : Entity
{
public string Name { get; set; }
public ICollection<LocalizedProperty> LocalizedProperties { get; set; }
}
public class Product : Entity
{
public string Name { get; set; }
public ICollection<LocalizedProperty> LocalizedProperties { get; set; }
}
public class LocalizedProperty : Entity
{
public string CultureName { get; set; }
public string PropertyName { get; set; }
public string PropertyValue { get; set; }
}
Is it possible to use a type discriminator along with the entity's Id as the foreign key. The idea is that the resultant LocalizedProperties table would be:
LocalizedProperties
-------------------
Id
EntityType
EntityId
CultureName
PropertyName
PropertyValue
I know this is possible using Table-per-subclass mapping where each of my "Localized" entities inherit from a base localized entity class, which in turn has the association with LocalizedProperty. However, I would rather not have this extra level of inheritance if the above is possible.
Thanks,
Ben
UPDATE
Thanks to Diego for providing the solution using confORM. For those of you using traditional mapping files, I have converted the example from http://fabiomaulo.blogspot.com/2010/11/conform-any-to-many.html
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="ConfOrm.UsageExamples.CreateXmlMappingsInBinFolder" assembly="ConfOrm.UsageExamples" xmlns="urn:nhibernate-mapping-2.2">
<class name="Blog">
<id name="Id" type="Guid">
<generator class="guid.comb" />
</id>
<property name="Title" />
<property name="Subtitle" />
<set name="Tags" cascade="all" where="TagedItemClass = 'ConfOrm.UsageExamples.CreateXmlMappingsInBinFolder.Blog'">
<key column="TagedItemId" foreign-key="none" />
<one-to-many class="Tag" />
</set>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="ConfOrm.UsageExamples.CreateXmlMappingsInBinFolder" assembly="ConfOrm.UsageExamples" xmlns="urn:nhibernate-mapping-2.2">
<class name="Tag">
<id name="Id" type="Guid">
<generator class="guid.comb" />
</id>
<property name="Name" />
<any id-type="Guid" name="TagedItem">
<column name="TagedItemClass" />
<column name="TagedItemId" />
</any>
</class>
</hibernate-mapping>
You can use <any>.
http://nhibernate.info/doc/nh/en/index.html#mapping-types-anymapping
For a full example, check http://fabiomaulo.blogspot.com/2010/11/conform-any-to-many.html. I think it's exactly what you need.

How to query collections in NHibernate

I have a class:
public class User
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IDictionary<string, string> Attributes { get; set; }
}
and a mapping file:
<class name="User" table="Users">
<id name="Id">
<generator class="hilo"/>
</id>
<property name="Name"/>
<map name="Attributes" table="UserAttributes">
<key column="UserId"/>
<index column="AttributeName" type="System.String"/>
<element column="Attributevalue" type="System.String"/>
</map>
</class>
So now I can add many attributes and values to a User.
How can I query those attributes so I can get ie.
Get all the users where attributename is "Age" and attribute value is "20" ?
I don't want to do this in foreach because I may have millions of users each having its unique attributes.
Please help
You can do it using HQL.
For example:
from User u join u.Attributes attr
where index(attr) = 'Age' and attr = '20'

NHibernate property mapping: columns and formula

When i map columns from the inspected table, i do this:
<property name="InstanceName" type="MyNameUserType, MyApp.MyNamespace">
<column name="Name"/>
<column name="Name2"/>
</property>
How can I make property mapping initialize a UserType with data retrieved by the formula's sql query?
<property name="InstanceName" type="MyNameUserType, MyApp.MyNamespace" formula="(...)"/>
fails with an exception "wrong number of columns".
Thanks in advance!
MyUserNameType should be a class level mapping so that you can map the result of the SQL function to a class. See these two posts for some possible help:
Class and SQL Function example: http://thoughtspam.spaces.live.com/blog/cns!253515AE06513617!478.entry
NHibernate Mapping with formula mapping example:
http://thoughtspam.spaces.live.com/blog/cns!253515AE06513617!477.entry
I'm the author of the articles referenced by Michael. I had no idea people where still interested and I'm not sure it's applicable with the latest NHibernate.
Here's a fresh link though: http://thoughtspam.wordpress.com/2007/12/19/nhibernate-property-with-formula/
example, using Northwind...
Mapping:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="PropertyFormulaExample.Shipper, PropertyFormulaExample" table="Shippers" lazy="false" >
<id name="ShipperID" column="ShipperID" unsaved-value="0">
<generator class="native" />
</id>
<property name="CompanyName" column="CompanyName" />
<property name="Phone" column="Phone" />
</class>
</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="PropertyFormulaExample.Order, PropertyFormulaExample" table="Orders" lazy="false">
<id name="OrderID" column="OrderID" unsaved-value="0">
<generator class="native" />
</id>
<property name="CustomerID" column="CustomerID" />
<property name="ShipVia" type="PropertyFormulaExample.Shipper, PropertyFormulaExample" formula="dbo.GetShipper(shipvia)" />
</class>
</hibernate-mapping>
Entities:
public class Order
{
public int OrderID { get; set; }
public string CustomerID { get; set; }
public Shipper ShipVia { get; set; }
}
public class Shipper : ILifecycle
{
public int ShipperID { get; set; }
public string CompanyName { get; set; }
public string Phone { get; set; }
#region ILifecycle Members
public LifecycleVeto OnDelete(NHibernate.ISession s)
{
throw new NotImplementedException();
}
public void OnLoad(NHibernate.ISession s, object id)
{
}
public LifecycleVeto OnSave(NHibernate.ISession s)
{
throw new NotImplementedException();
}
public LifecycleVeto OnUpdate(NHibernate.ISession s)
{
throw new NotImplementedException();
}
#endregion
}
And finally the SQL function:
CREATE FUNCTION dbo.GetShipper(#shipperId int)
RETURNS int
AS
BEGIN
RETURN #shipperId
END
Obviously, you’ll want the function to do something meaningful, but the idea is you return the PK for the entity and implement ILifecycle.