2009-05-22 12 views
27

Suponiendo que el siguiente escenario:NHibernate - createCriteria vs CreateAlias ​​

class Project{ 
    public Job Job; 
} 

class Job{ 
    public Name; 
} 

Suponiendo que quiero usar la API Criterios para buscar todos los proyectos cuyo trabajo tiene el nombre "sumthing".

Podría usar CreateAlias ​​para crear un alias para Job y usarlo para acceder a Nombre, o podría crear un nuevo Criterio para la propiedad Trabajo y buscar por Nombre.

Rendimiento sabio, ¿hay alguna diferencia?

Respuesta

38

dado a estos requisitos no habría ninguna diferencia, el SQL generado es el mismo: para las asignaciones:

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

y clases

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

estos criterios definiciones

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

generar el mismo 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' 

en cuenta sin embargo que el CreateAlias se basa en las asignaciones para generar asociaciones mientras que la llamada CreateCriteria permite especificar JoinType.

así, estas llamadas

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

generan estas sentencias 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

¿Pero puede especificar el tipo de unión en la sobrecarga CreateAlias? CreateAlias ​​siempre parece ser una combinación interna para mí de forma predeterminada ... incluso cuando el uno a uno permite valores nulos. – dotjoe

+4

Sí, con NH2 ++ CreateAlias ​​también permite especificar un Tipo de Unión que anula las asociaciones mapeadas. Supongo que dado que CreateCriteria devuelve un objeto ICriteria ("rooteado" en la entidad asociada), es posible generar consultas diferentes (avanzadas) ya que las ICriteria generadas se pueden manipular de múltiples maneras. – Jaguar

7

createAlias ​​() devuelve criterios originales como es resultado createCriteria() devuelve nuevos criterios construidos con createCriteria

diferencia será cuando los métodos de encadenamiento, por ejemplo

cr.createAlias ​​(). Add (Restrictions.ilike ("código", "abc")) se sumará a la restricción entidad cr.createCriteria ("padre", "p"). Add (Restrictions.ilike ("código", "abc")) agregará restricción a su elemento principal

22

Para explicar la diferencia entre CreateCriteria y CreateAlias ​​en NHibernate 2.0 + veamos el siguiente modelo de 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; } 
} 

Ahora si usted escribe siguientes criterios de combinación interna de estas entidades

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

Los criterios anteriores no trabajará porque cuando la primera createCriteria lo ejecuta volver "Categoría" entidad, por lo tanto, cuando el segundo createCriteria lo ejecutan no encontrará propiedades ProductStocks en la entidad "Categoría" y la consulta fallará.

Así que la forma correcta de escribir este criterio es

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

Cuando los primeros CreateAlias ​​corre devuélvalo "Producto" entidad, cuando el segundo createCriteria ejecutan encontrará ProductStocks de propiedad en la entidad "Producto".

Así que el TSQL será así.

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 

Espero que esto ayude.

+0

Esto tiene mucho sentido y responde la pregunta original. – Oliver

Cuestiones relacionadas