2009-05-22 7 views
27

Zakładając następujący scenariusz:NHibernate - CreateCriteria vs CreateAlias ​​

class Project{ 
    public Job Job; 
} 

class Job{ 
    public Name; 
} 

Zakładając chcę użyć API kryteria, aby wyszukać wszystkie projekty, których praca ma nazwę „sumthing”.

Mogłabym użyć CreateAlias ​​do stworzenia aliasu dla Job i użyć go do uzyskania dostępu do Name, lub mógłbym stworzyć nowe Criteria dla właściwości Job i search by Name.

Pewność, czy jest jakakolwiek różnica?

Odpowiedz

38

podane tych wymogów nie będzie żadnej różnicy, wygenerowane SQL jest taka sama: dla odwzorowań:

<?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> 

i ćwiczenia

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; } 
    } 

kryteria te definicje

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")); 

wygenerować ten sam 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' 

uwaga jednak, że CreateAlias opiera się na przekształceniach wygenerować skojarzenia natomiast wywołanie CreateCriteria pozwala określić JoinType.

więc takie rozmowy

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")); 

wygenerować te instrukcje 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' 
+1

Ale można określić typ łączenia w Przeciążenie CreateAlias? CreateAlias ​​zawsze wydaje się domyślnym łączeniem wewnętrznym dla mnie ... nawet gdy wiele do jednego dopuszcza wartości zerowe. – dotjoe

+4

Tak, z NH2 ++ funkcja CreateAlias ​​pozwala również określić typ JoinType nadpisujący skojarzenia mapowane. Zgaduję, że ponieważ CreateCriteria zwraca obiekt ICriteria ("rooted" w powiązanej encji) może być możliwe generowanie różnych (zaawansowanych) zapytań, ponieważ wygenerowane ICriteria mogą być manipulowane na wiele sposobów. – Jaguar

7

createAlias ​​() zwraca oryginalne kryteria to spowodować createCriteria() zwraca nowe kryteria zbudowane z createCriteria

różnica będzie, gdy metody łańcuchowe np

cr.createAlias ​​(), dodano (Restrictions.ilike ("kodu", "abc")) doda ograniczenie do jednostki cr.createCriteria ("rodzic", "P"). Add (Restrictions.ilike ("code", "abc")) doda ograniczenie do rodzica

22

Aby wyjaśnić różnicę między CreateCriteria i CreateAlias ​​w NHibernate 2.0 + pozwala zobaczyć następujący model domeny.

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; } 
} 

Teraz jeśli piszesz następujące kryteria do sprzężenia wewnętrznego tych podmiotów

var criteria = DetachedCriteria.For<Product>() 
       .CreateCriteria("Category", JoinType.InnerJoin) 
       .CreateCriteria("ProductStocks", "ps", JoinType.InnerJoin) 
       .Add(Restrictions.Le("ps.Stock",10)); 

Powyższe kryteria nie będzie działać, bo gdy pierwszy CreateCriteria prowadzi to return „Kategoria” podmiot, zatem gdy drugie CreateCriteria go wykonać nie znajdę właściwości ProductStocks w encji "Category", a zapytanie nie powiedzie się.

więc poprawny sposób napisać powyższe kryteria jest

var criteria = DetachedCriteria.For<Product>() 
       .CreateAlias("Category", "c", JoinType.InnerJoin) 
       .CreateCriteria("ProductStocks", "ps", JoinType.InnerJoin) 
       .Add(Restrictions.Le("ps.Stock",10)); 

Po pierwsze CreateAlias ​​przebiega powrót „Produkt” podmiot, gdy drugie CreateCriteria wykonać znajdzie ProductStocks własności w „produkt” podmiotu.

Tak więc TSQL będzie taki.

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 

Mam nadzieję, że to pomoże.

+0

To ma wiele sensu i odpowiada na oryginalne pytanie. – Oliver