2009-10-20 8 views
5

Je travaille sur la mise en place d'une simple application POC en utilisant Fluent NHibernate pour essayer de montrer qu'elle peut faire tout notre outil d'accès aux données actuel et bien plus encore. L'un des cas marginaux que mon patron s'inquiète est la possibilité d'accéder à plusieurs schémas dans la même base de données en une seule requête. Jusqu'à présent, j'ai pu extraire des données de tables dans les deux schémas tant que la requête ne touche qu'un seul schéma à la fois. Si j'essaie d'exécuter une commande qui rejoindra les tables des deux schémas, cela explosera. Sur la base des messages d'erreur que je vois, je ne crois pas que le problème est avec la jointure à travers les schémas, mais plutôt avec le fait que les deux champs dont j'ai besoin pour joindre les tables sont tous les deux non-clés des champs. La structure de la table deux est quelque chose comme ceci:Joignez-vous entre deux champs non-clés

 
Customer (in schema 1) 
-------- 
int CustomerId (Primary Key) 
string Name 
...other fields 

Order (in schema 2) 
-------- 
int OrderId (primary key) 
string CustomerName 
...other fields 

l'aide de sql directement je peux rejoindre sur le nom/champs CustomerName et obtenir les données des deux tables. Cependant, en utilisant NHibernate, je continue à obtenir une "System.FormatException: la chaîne d'entrée n'était pas dans un format correct" lorsque vous essayez d'extraire des données de la table Order et d'inclure des données de la table Customer. Cela m'amène à croire que NHibernate essaie de se joindre au champ CustomerName et au champ CustomerId.

Je sais comment lui dire d'utiliser le champ CustomerName dans mon mappage d'ordre, mais je ne peux pas trouver un moyen de dire à rejoindre sur le champ Nom de la table client.

Mes Mappages ressemblent à ceci:

public class CustomerMap : ClassMap<Customer> 
{ 
    public CustomerMap() 
    { 
     Id(x => x.Id) 
      .Column("CustomerId"); 
     Map(x => x.Name); 
    } 
} 


public class OrderMap : ClassMap<Order> 
{ 
    public OrderMap() 
    { 
     Schema("schema2"); 
     Id(x => x.Id) 
      .Column("OrderID"); 
     Map(x => x.CustomerName) 
      .Column("CustomerName"); 
     References<Customer>(x => x.Customer, "CustomerName"); 
    } 
} 

SQL j'écrire pour obtenir les résultats que je veux serait quelque chose comme:

select o.OrderId, o.CustomerName, c.CustomerId 
from order o 
inner join customer c on c.Name = o.CustomerName 

Est-ce même possible? Existe-t-il une façon différente/meilleure de s'y prendre?

Répondre

6

Je n'ai pas travaillé avec plusieurs schémas, mais l'approche que j'ai trouvé pour la cartographie des champs non-clés est la suivante:

En OrderMap ... Références (ordre => order.Customer). Colonne ("CustomerName"). PropertyRef ("Nom");

Lorsque PropertyRef ("Nom") fait référence à la propriété Name de votre classe Customer (que vous définissez dans CustomerMap).

Je ne fais que commencer avec FNH, donc vous pouvez trouver une meilleure solution, mais j'espère que cela aide.

+0

Merci! C'est ce qu'il a fait. J'avais essayé individuellement 'Column' et 'PropertyRef', mais je n'ai pas pensé à les essayer ensemble pour une raison quelconque. – Hamman359

+0

Super, c'est exactement ce que je cherchais. Vous pouvez également bénéficier d'un typage fort avec votre paramètre PropertyRef en utilisant plutôt lambdas, c'est-à-dire PropertyRef (x => x.Name). Cela signifie qu'il ne se cassera pas si vous refactorisez votre classe de client. – nukefusion

+0

Cela a aidé même avec un à plusieurs! :) – Turowicz

0

Rejoindre dans les schémas est pas de problème, il vous suffit de spécifier le schéma dans votre application:

public sealed class CustomerMap : ClassMap<Customer> 
{ 
    public CustomerMap() 
    { 
     Table("Customer"); 
     Schema("dbo"); 
     // etc. 
    } 
} 

Votre table de commande devrait avoir CustomerId comme une clé étrangère, non CustomerName. C'est la manière standard d'implémenter une relation un-à-plusieurs et n'est pas spécifique à NHibernate. Si vous avez cela, la mise en correspondance dans OrderMap est:

References(x => x.Customer, "CustomerId"); 
+0

Merci, mais cela ne répond pas vraiment à ma question. Comme je l'ai indiqué, je savais déjà comment référencer un schéma différent. Mon problème était quand j'ai essayé de rejoindre les deux tables. Aussi, bien que je sois d'accord que la clé étrangère doit être CustomerId et non CustomerName, ce n'est pas possible dans ce cas car ce système est déjà dans PROD depuis presque un an et je n'ai aucun contrôle sur le schéma qui aurait besoin d'être modifié changement. Compte tenu de cette limitation, je dois rejoindre sur les champs de chaîne. La réponse de David indique l'approche que j'ai pu utiliser pour résoudre ce problème. – Hamman359

1

Je donne par exemple comment pouvez-vous associez champs NON clés dans Hibernate en utilisant l'annotation.
Veuillez le convertir en nHibernate correspondant.

CREATE TABLE `Customer` (
    `CUSTOMER_ID` bigint(20) NOT NULL AUTO_INCREMENT, 
    `NAME` varchar(100) NOT NULL, 
    PRIMARY KEY (`CUSTOMER_ID`) 
) 

CREATE TABLE `Order` (
    `ORDER_ID` bigint(20) NOT NULL AUTO_INCREMENT, 
    `CUSTOMER_NAME` varchar(100) NOT NULL, 
    PRIMARY KEY (`ORDER_ID`) 
) 

Entité client

@Entity 
@Table(name = "CUSTOMER") 
public class Customer{ 

    private long customerId; 
    private String name; 
    private Order order; 


    public Customer() { 
    } 

    public Customer(String name) { 
     this.name= name; 

    } 

    @Id 
    @GeneratedValue 
    @Column(name = "CUSTOMER_ID") 
    public long getCustomerId() { 
     return this.customerId; 
    } 

    public void setCustomerId(long customerId) { 
     this.customerId= customerId; 
    } 

    @Column(name = "NAME", nullable = false, length = 100, insertable=false, updatable=false) 
    public String getName() { 
     return this.name; 
    } 
    public String setName(String name) { 
     return this.name; 
    } 

    @ManyToOne 
    @JoinColumn(name = "NAME", referencedColumnName = "CUSTOMER_NAME") 
    public Order getOrder() { 
     return order; 
    } 


    public void setOrder(Order order) { 
     this.order= order; 
    } 


} 

Ordre Entité

@Entity 
@Table(name = "ORDER") 
public class Order implements Serializable { 

    private long orderId; 
    private String customerName; 

    public Ortder() { 
    } 

    public Order(String customerName) { 
     this.customerName= customerName; 

    } 

    @Id 
    @GeneratedValue 
    @Column(name = "ORDER_ID") 
    public long getOrderId() { 
     return this.orderId; 
    } 

    public void setOrderId(long orderId) { 
     this.orderId= orderId; 
    } 

    @Column(name = "CUSTOMER_NAME", nullable = false, length=250) 
    public String getCustomerName() { 
     return this.customerName; 
    } 

    public void setCustomerName(String customerName) { 
     this.customerName= customerName; 
    } 


} 

Customer customer = new Customer("C1"); 
session.load(customer , 5L);  
System.out.println(customer.getName()); 
Order order = customer.getOrder(); 
System.out.println(order.getCustomerName()); 

SQL sera générer d like (J'ai supprimé l'alias généré par Hibernate)

select customer.CUSTOMER_ID, customer.NAME, order.ORDER_ID, 
order.CUSTOMER_NAME 
from CUSTOMER 
left outer join ORDER **on NAME=CUSTOMER_NAME** where CUSTOMER_ID=?