Assuming the following scenario:
class Project{ public Job Job; } class Job{ public Name; }
Assuming I want to use the Criteria API to search for all projects whose Job has the name "sumthing".
I could use the CreateAlias to create an alias for Job and use it to access Name, or I could create a new Criteria for the property Job and search by Name.
Performance wise, is there any difference?
createAlias(String associationPath, String alias) Join an association, assigning an alias to the joined association. Criteria. createAlias(String associationPath, String alias, int joinType) Join an association using the specified join-type, assigning an alias to the joined association.
The "projection" is kind of like plucking out what data you will need so that NHibernate only asks the database for just that data when it makes the SQL.
The DetachedCriteria class lets you create a query outside the scope of a session, and then later execute it using some arbitrary ISession. A DetachedCriteria may also be used to express a sub-query. ICriterion instances involving sub-queries may be obtained via Subqueries.
given these requirements there would be no difference, the generated SQL is the same: for mappings:
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> <class name="Project" table="Project"> <id name="Id" type="Int32" unsaved-value="0"> <column name="Id" sql-type="int" not-null="true" unique="true"/> <generator class="native" /> </id> <many-to-one name="Job" column="FK_JobId" cascade="save-update" not-null="true" /> </class> </hibernate-mapping> <?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> <class name="Job" table="Job"> <id name="Id" type="Int32" unsaved-value="0"> <column name="Id" sql-type="int" not-null="true" unique="true"/> <generator class="native" /> </id> <property name="Name" type="String"> <column name="Name" sql-type="nvarchar" length="50" not-null="true"/> </property> </class> </hibernate-mapping>
and classes
public class Project { public Project() { } public virtual int Id { get; set; } public virtual Job Job { get; set; } } public class Job { public Job() { } public virtual int Id { get; set; } public virtual String Name { get; set; } }
these criteria definitions
ICriteria criteriacrit = session .CreateCriteria(typeof (Project)) .CreateCriteria("Job", "job") .Add(Restrictions.Eq("job.Name", "sometextA")); ICriteria aliascrit = session .CreateCriteria(typeof (Project)) .CreateAlias("Job", "job") .Add(Restrictions.Eq("job.Name", "sometextB"));
generate the same SQL
SELECT this_.Id as Id2_1_, this_.FK_JobId as FK2_2_1_, job1_.Id as Id1_0_, job1_.Name as Name1_0_ FROM Project this_ inner join Job job1_ on this_.FK_JobId=job1_.Id WHERE job1_.Name = @p0; @p0 = 'sometextA' SELECT this_.Id as Id2_1_, this_.FK_JobId as FK2_2_1_, job1_.Id as Id1_0_, job1_.Name as Name1_0_ FROM Project this_ inner join Job job1_ on this_.FK_JobId=job1_.Id WHERE job1_.Name = @p0; @p0 = 'sometextB'
note however that the CreateAlias
relies on the mappings to generate associations whereas the CreateCriteria
call allows to specify JoinType
.
so, these calls
ICriteria criteriacrit = session .CreateCriteria(typeof(Project)) .CreateCriteria("Job",JoinType.LeftOuterJoin) .Add(Restrictions.Eq("Name", "sometextA")); ICriteria aliascrit = session .CreateCriteria(typeof (Project)) .CreateAlias("Job", "job") .Add(Restrictions.Eq("job.Name", "sometextB"));
generate these SQL statements
SELECT this_.Id as Id2_1_, this_.FK_JobId as FK2_2_1_, job1_.Id as Id1_0_, job1_.Name as Name1_0_ FROM Project this_ **left outer** join Job job1_ on this_.FK_JobId=job1_.Id WHERE job1_.Name = @p0; @p0 = 'sometextA' SELECT this_.Id as Id2_1_, this_.FK_JobId as FK2_2_1_, job1_.Id as Id1_0_, job1_.Name as Name1_0_ FROM Project this_ **inner join** Job job1_ on this_.FK_JobId=job1_.Id WHERE job1_.Name = @p0; @p0 = 'sometextB'
To explain the difference between CreateCriteria and CreateAlias in NHibernate 2.0 + lets see the following domain model.
public class Product { public virtual int Id { get; private set; } public virtual string Name { get; set; } public virtual decimal Price { get; set; } public virtual Category Category { get; set; } public virtual IList<ProductStock> ProductStocks { get; set; } } public class Category { public virtual int Id { get; private set; } public virtual string Name { get; set; } public virtual IList<Product> Products { get; set; } } public class ProductStock { public virtual int Id { get; private set; } public virtual Product Product { get; set; } public virtual string WarehouseName { get; set; } public virtual int Stock { get; set; } }
Now if you write following criteria to inner join these entities
var criteria = DetachedCriteria.For<Product>() .CreateCriteria("Category", JoinType.InnerJoin) .CreateCriteria("ProductStocks", "ps", JoinType.InnerJoin) .Add(Restrictions.Le("ps.Stock",10));
The above criteria wont work because when the first CreateCriteria runs it return "Category" entity, therefore when the second CreateCriteria execute it wont find property ProductStocks in the "Category" entity and the query will fail.
So the correct way to write this criteria is
var criteria = DetachedCriteria.For<Product>() .CreateAlias("Category", "c", JoinType.InnerJoin) .CreateCriteria("ProductStocks", "ps", JoinType.InnerJoin) .Add(Restrictions.Le("ps.Stock",10));
When the first CreateAlias runs it return "Product" entity, when the second CreateCriteria execute it will find property ProductStocks in the "Product" entity.
So the TSQL will be like this.
SELECT this_.ProductID as ProductID8_2_, this_.Name as Name8_2_, this_.Price as Price8_2_, this_.CategoryID as CategoryID8_2_, ps2_.ProductStockID as ProductS1_9_0_, ps2_.Stock as Stock9_0_, ps2_.ProductID as ProductID9_0_, ps2_.WarehouseID as Warehous4_9_0_, c1_.CategoryID as CategoryID0_1_, c1_.Name as Name0_1_ FROM [Product] this_ inner join [ProductStock] ps2_ on this_.ProductID = ps2_.ProductID inner join [Category] c1_ on this_.CategoryID = c1_.CategoryID WHERE ps2_.Stock <= 10
I hope this will help.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With