【问题标题】:Join between two non-key fields两个非关键字段之间的连接
【发布时间】:2011-10-28 04:17:30
【问题描述】:

我正在使用 Fluent NHibernate 构建一个简单的 POC 应用程序,试图证明它可以完成我们当前的手动数据访问工具的所有工作等等。我的老板担心的边缘情况之一是能够在一个查询中访问同一数据库中的多个模式。到目前为止,只要查询一次只触及一个模式,我就能够从两种模式中的表中提取数据。如果我尝试执行一个将两个模式中的表连接起来的命令,它就会爆炸。

根据我看到的错误消息,我认为问题不在于跨模式加入,而是因为我需要加入表的两个字段都是非关键字段.这两个表的结构是这样的:

客户(在模式 1 中) -------- int CustomerId(主键) 字符串名称 ...其他领域 顺序(在模式 2 中) -------- int OrderId(主键) 字符串客户名称 ...其他领域

直接使用 sql 我可以加入 Name/CustomerName 字段并从两个表中获取数据。但是,使用 NHibernate 在尝试从 Order 表中提取数据并包含 Customer 表中的数据时,我不断收到“System.FormatException:输入字符串格式不正确”。这让我相信 NHibernate 正在尝试加入 CustomerName 字段和 CustomerId 字段。

我知道如何告诉它在我的 Order 映射中使用 CustomerName 字段,但我想不出一种方法来告诉它加入 Customer 表的 Name 字段。

我的映射如下所示:

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 类似于:

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

这甚至可能吗? 有没有其他/更好的方法来解决这个问题?

【问题讨论】:

    标签: nhibernate fluent-nhibernate


    【解决方案1】:

    我没有使用多个模式,但我发现映射非关键字段的方法如下:

    在 OrderMap 中... References(order => order.Customer).Column("CustomerName").PropertyRef("Name");

    PropertyRef("Name") 实际上是指您的 Customer 类上的 Name 属性(您将在 CustomerMap 中定义)。

    我刚刚开始使用 FNH,因此您可能会找到更好的解决方案,但我希望这会有所帮助。

    【讨论】:

    • 谢谢!做到了。我曾分别尝试过 'Column' 和 'PropertyRef',但由于某种原因没有考虑将它们一起尝试。
    • 太好了,这正是我想要的。您还可以通过使用 lambda 来使用 PropertyRef 参数从强类型中受益,即 PropertyRef(x => x.Name)。这意味着如果您重构您的 Customer 类,它不会中断。
    • 当我收到以下错误时,这为我解决了一个问题。 “无法初始化集合:输入字符串 'apr234' 的格式不正确。”我有两个表通过一个不是主键的列关联。将 PropertyRef 添加到我现有的映射中,解决了这个错误。
    【解决方案2】:

    我正在举例说明如何使用注释在 Hibernate 中映射非关键字段。
    请转换成对应的nHibernate。

    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`)
    )
    

    客户实体

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

    订单实体

    @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 会像这样生成(我已经删除了 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=?
    

    【讨论】:

      【解决方案3】:

      跨架构连接没问题,您只需要在映射中指定架构:

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

      您的订单表应该有 CustomerId 作为外键,而不是 CustomerName。这是实现一对多关系的标准方式,并不是 NHibernate 特有的。如果你有,OrderMap 中的映射是:

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

      【讨论】:

      • 谢谢,但这并不能真正解决我的问题。正如我所指出的,我已经知道如何引用不同的模式。我的问题是当我尝试加入这两个表时。此外,虽然我同意外键应该是 CustomerId 而不是 CustomerName,但在这种情况下这是不可能的,因为该系统已经在 PROD 中使用了将近一年,而且我无法控制需要修改以实现此目的的架构改变。鉴于这个限制,我需要加入字符串字段。 David 的回答表明了我能够用来解决这个问题的方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-06
      • 2017-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多