2009-05-22 6 views
27

En supposant que le scénario suivant:NHibernate - createCriteria vs createAlias ​​

class Project{ 
    public Job Job; 
} 

class Job{ 
    public Name; 
} 

En supposant que je veux utiliser l'API de critères pour rechercher tous les projets dont le travail a le nom « Sumthing ».

Je pourrais utiliser CreateAlias ​​pour créer un alias pour Job et l'utiliser pour accéder à Name, ou je pourrais créer un nouveau critère pour la propriété Job et effectuer une recherche par Name.

Performance sage, y a-t-il une différence?

Répondre

38

compte tenu de ces exigences, il n'y aurait pas de différence, le SQL généré est le même: pour applications:

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

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

ces critères définitions

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

générer le même 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 cependant que la CreateAlias repose sur les applications pour générer des associations alors que l'appel CreateCriteria permet de spécifier JoinType.

donc, ces appels

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

génèrent ces instructions 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

Mais vous pouvez spécifier le type de jointure dans la surcharge CreateAlias? CreateAlias ​​semble toujours utiliser par défaut la jointure interne pour moi ... même lorsque le multiple-to-one autorise les valeurs nulles. – dotjoe

+4

Oui avec NH2 ++ le CreateAlias ​​permet également de spécifier un JoinType remplaçant les associations mappées. Je suppose que puisque le CreateCriteria renvoie un objet ICriteria ("rooted" à l'entité associée) il peut être possible de générer des requêtes différentes (avancées) puisque les ICriteria générées peuvent être manipulées de plusieurs manières. – Jaguar

7

createAlias ​​() renvoie les critères originaux est le résultat createCriteria() renvoie de nouveaux critères construits avec createCriteria

différence sera lors de l'enchaînement des méthodes par exemple Cr.createAlias ​​(). Add (Restrictions.ilike ("code", "abc")) ajoutera une restriction à l'entité. cr.createCriteria ("parent", "p"). Add (Restrictions.ilike ("code", "abc")) va ajouter une restriction à son parent

22

Pour expliquer la différence entre CreateCriteria et CreateAlias ​​dans NHibernate 2.0 + permet de voir le modèle de domaine suivant.

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

Maintenant, si vous écrivez des critères suivants à jointure interne ces entités

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

Les critères ci-dessus ne vais pas travailler parce que quand la première createCriteria exécute retour entité « Catégorie », donc lorsque le second createCriteria l'exécuter ne trouvera pas la propriété ProductStocks dans l'entité "Category" et la requête échouera.

Ainsi, la manière correcte d'écrire ce critère est

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

Lorsque les premiers createAlias ​​l'exécute retour entité « produit », lorsque le second createCriteria exécutent il trouvera ProductStocks de propriété dans l'entité « produit ».

Donc le TSQL sera comme ça.

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 

J'espère que cela aidera.

+0

Cela fait beaucoup de sens et répond à la question initiale. – Oliver