NHibernate - CreateCriteria против CreateAlias
Предполагая следующий сценарий:
class Project{
public Job Job;
}
class Job{
public Name;
}
Предполагая, что я хочу использовать Criteria API для поиска всех проектов, чье задание имеет название "sumthing".
Я мог бы использовать CreateAlias для создания псевдонима для Job и использовать его для доступа к Name или создать новый критерий для свойства Job и выполнить поиск по Name.
Производительность мудрая, есть ли разница?
3 ответа
Учитывая эти требования, разницы не будет, сгенерированный SQL такой же: для отображений:
<?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>
и классы
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; }
}
эти критерии определения
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"));
генерировать тот же 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'
обратите внимание, однако, что CreateAlias
опирается на отображения для создания ассоциаций, тогда как CreateCriteria
звонок позволяет указать JoinType
,
Итак, эти звонки
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"));
генерировать эти операторы 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_
**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'
Чтобы объяснить разницу между CreateCriteria и CreateAlias в NHibernate 2.0 +, давайте рассмотрим следующую модель домена.
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; }
}
Теперь, если вы напишите следующие критерии для внутреннего объединения этих объектов
var criteria = DetachedCriteria.For<Product>()
.CreateCriteria("Category", JoinType.InnerJoin)
.CreateCriteria("ProductStocks", "ps", JoinType.InnerJoin)
.Add(Restrictions.Le("ps.Stock",10));
Приведенные выше критерии не будут работать, поскольку при первом запуске CreateCriteria он возвращает сущность "Category", поэтому при выполнении второго CreateCriteria он не найдет свойство ProductStocks в сущности "Category", и запрос не будет выполнен.
Таким образом, правильный способ написать этот критерий
var criteria = DetachedCriteria.For<Product>()
.CreateAlias("Category", "c", JoinType.InnerJoin)
.CreateCriteria("ProductStocks", "ps", JoinType.InnerJoin)
.Add(Restrictions.Le("ps.Stock",10));
Когда запускается первый CreateAlias, он возвращает сущность "Product", а когда исполняется второй CreateCriteria, он находит свойство ProductStocks в сущности "Product".
Так что TSQL будет таким.
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
Я надеюсь, это поможет.
createAlias () возвращает исходные критерии, как результат.createCriteria() возвращает новые критерии, созданные с помощью createCriteria.
Разница будет при цепочке методов, например,
cr.createAlias (). add (Restrictions.ilike ("code", "abc")) добавит ограничение к сущности cr.createCriteria ("parent", "p"). add (Restrictions.ilike ("code", " abc ")) добавит ограничение своему родителю