2009-05-22 9 views
27

Supponendo che il seguente scenario:NHibernate - createCriteria vs CREATEALIAS

class Project{ 
    public Job Job; 
} 

class Job{ 
    public Name; 
} 

Supponendo che voglio utilizzare l'API Criteri per la ricerca di tutti i progetti il ​​cui lavoro ha il nome di "Sumthing".

Potrei usare CreateAlias ​​per creare un alias per Job e usarlo per accedere a Name, oppure potrei creare un nuovo criterio per la proprietà Job e cercare per nome.

Per quanto riguarda le prestazioni, c'è qualche differenza?

risposta

38

proposta questi requisiti non ci sarebbe alcuna differenza, l'SQL generato è lo stesso: per mappature:

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

e classi

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

questi criteri delle definizioni

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

generare lo stesso 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' 

nota tuttavia che la CreateAlias si basa sulle mappature per generare le associazioni, mentre la chiamata CreateCriteria permette di specificare JoinType.

così, queste chiamate

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

generano queste istruzioni 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

Ma è possibile specificare il tipo di join nel sovraccarico di CreateAlias? CreateAlias ​​sembra sempre predefinito per inner join per me ... anche quando il many-to-one consente i null. – dotjoe

+4

Sì con NH2 ++ il CreateAlias ​​consente anche di specificare un JoinType che sovrascrive le associazioni mappate. Immagino che, dal momento che CreateCriteria restituisce un oggetto ICriteria ("rooted" nell'entità associata), è possibile generare query (avanzate) diverse poiché l'ICriteria generato può essere manipolato in diversi modi. – Jaguar

7

CREATEALIAS() restituisce criteri originali come è risultato createCriteria() restituisce nuovi criteri costruiti con createCriteria

differenza sarà quando si concatenano metodi ad es

cr.createAlias ​​(). Aggiungere (Restrictions.ilike ("codice", "abc")) aggiungerà restrizione entità cr.createCriteria ("padre", "p"). Aggiungere (Restrictions.ilike ("code", "abc")) aggiungerà restrizione al suo genitore

22

Per spiegare la differenza tra CreateCriteria e CreateAlias ​​in NHibernate 2.0 + è possibile visualizzare il seguente modello di dominio.

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

Ora, se si scrive seguenti criteri per unirsi interno queste entità

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

I criteri di cui sopra non funzionerà, perché quando la prima createCriteria gestisce tornare "Categoria" entità, quindi, quando il secondo createCriteria eseguirlo non troverai PropertyStock di proprietà nell'entità "Categoria" e la query fallirà.

Quindi il modo corretto di scrivere questo criterio è

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

Quando i primi CREATEALIAS corre lo tornare "Prodotto" entità, quando il secondo createCriteria eseguono troverà ProductStocks proprietà nell'entità "Prodotto".

Quindi il TSQL sarà così.

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 

Spero che questo possa essere d'aiuto.

+0

Questo ha molto senso e risponde alla domanda originale. – Oliver