流利的NHibernate - 如何将外键列映射为一个属性 [英] Fluent NHibernate - How to map the foreign key column as a property

查看:153
本文介绍了流利的NHibernate - 如何将外键列映射为一个属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我相信这是一个直截了当的问题,但考虑如下:
我在公司和部门之间的参考如下:

  public class Company {
public Guid ID {get;组; }
公共部门部门{get;组; }
public Guid SectorID {get;组; }
}

public class Sector {
public Guid ID {get;组; }
public string Name {get;组; }
}

好的。我想要的是在我去之后公司对象的SectorID:

 (新公司())。Sector = new Sector(){Name =asdf} 

并执行刷新。 b
$ b

我使用的映射在公司表中的数据库中创建了一个名为Sector_Id的额外列,但是这不是公司的一个属性。我想要填写SectorID属性。



我现在在CompanyMap中使用的映射是

 引用(c => c.Sector).Cascade.All(); 

有人有什么想法吗?




感谢您的回复。
不幸的是,如果我做第二个选项(设置列的列名与属性相同,或设置 Map(x => x.SectorID,Sector_Id)那么我得到的错误:

System.IndexOutOfRangeException:此计数= 7的SqlParameterCollection索引7无效。



我可能不得不做第一个选项,但是我担心当您调用SectorID get时会触发额外的查询,因为它将数据块从数据库中取出(除非它是急于加载的,有点麻烦)。

我很惊讶,这不是一个简单的答案。






WOW!
如果我使用

  public virtual Guid SectorID 
{
get {return Sector.ID;
}

那么nhibernate就是足够聪明地知道组织查询中的Sector_id列与Sector.ID实际上是一样的,它将这个返回下来,它不会发送一个additi onal查询即使你懒加载。我印象深刻!




作为后续...似乎hibernate并没有真正写出来能够映射对象中的外键列。虽然这在Web前端可能会有点痛苦,但这确实是一个持久性问题,而不是真正的对象问题。
我正在使用asp.net MVC,并写了一个自定义模型联编程序,将采取名称联系人(而不是ContactID)的输入框,新建一个新的联系人与texbox中的什么,然后将其应用于模型的属性。这解决了Web前端下拉列表的问题。如果有人对此感兴趣,可以发布代码。

解决方案

这很容易用公式属性完成。

  public class Company {
public virtual Guid Id {get;组; }
公共虚拟Guid? SectorId {get;组; }
公共虚拟行业部门{get;组; }
}

public class CompanyMap:ClassMap< Company> {
public CompanyMap(){
Id(x => x.Id); //映射到名为Id的列
引用(x => x.Sector); //映射到名为Sector_id的列,除非您更改NHibernate默认映射规则。
Map(x => x.SectorId).Formula([Sector_id]);




$ p $这个应该是你想要的。当公司为新的时候, SectorId 将为空;当从数据库中提取公司时, SectorId 将填充给定的公式值。 SectorId 是作为一个属性公开的,这使得它非常适合处理web下拉等。当你保存时,你仍然需要绑定真实协会。假设 SectorId 在表单中被选中...


  using var txn = session.BeginTransaction()){
//设置FK引用。
company.Sector = session.Load< Sector>(company.SectorId);
//保存新记录。
session.Save(company);
//提交交易。
txn.Commit();
}


I am sure this is a straightforward question but consider the following: I have a reference between company and sector as follows:

public class Company {
    public Guid ID { get; set; }
    public Sector Sector { get; set; }
    public Guid SectorID { get; set; }
}

public class Sector {
    public Guid ID { get; set; }
    public string Name { get; set; }
}

Ok. What I want is the SectorID of the Company object to be populated after I go:

(new Company()).Sector = new Sector() { Name="asdf" }

and do a flush.

The mapping I am using kindly creates an additional column in the database called Sector_Id in the Company table, but this is not available as a property on Company. I want the SectorID property to be filled.

The mapping I'm currently using in the CompanyMap is

References(c => c.Sector).Cascade.All();

Does anyone have any ideas?


Thanks for your response. Sadly if I do the second option (set the column name of the column to be the same as the property, or set Map(x => x.SectorID, "Sector_Id") then I get the error:

System.IndexOutOfRangeException: Invalid index 7 for this SqlParameterCollection with Count=7.

I may have to do the first option but I am concerned that an additional query will be fired when you call the SectorID get as it gets the Sector itself out of the db (unless it is eager loaded which is a bit of a hassle).

I am surprised there is not an easy answer to this.


WOW! If I use

public virtual Guid SectorID
{
    get { return Sector.ID;
}   

then nhibernate is clever enough to know that the Sector_id column in the Organisation query is actually the same thing as Sector.ID and it returns this under the hoods. It does not send off an additional query even if you lazy load. I am impressed!


As a follow up... It seems that hibernate is not really written to be able to map the foreign key column in the objects. Although this can be a bit of a pain in web front ends it makes sense as this is really a persistence concern not really an object concern. I am using asp.net MVC and have written a custom model binder that will take a input box of name Contact (rather than ContactID), new up a new Contact with the ID of what is in the texbox, and then apply this to the property of the Model. This gets around the issue with dropdown lists in web front ends. Will post code if anyone is interested.

解决方案

This is easily done with a formula property.

public class Company {
  public virtual Guid Id { get; set; }
  public virtual Guid? SectorId { get; set; }
  public virtual Sector Sector { get; set; }
}

public class CompanyMap : ClassMap<Company> {
  public CompanyMap() {
    Id(x => x.Id); // Maps to a column named "Id"
    References(x => x.Sector); // Maps to a column named "Sector_id", unless you change the NHibernate default mapping rules.
    Map(x => x.SectorId).Formula("[Sector_id]");
  }    
}

This should act exactly how you want. When the Company is new, SectorId will be null; when Company is fetched from the DB, SectorId will be populated with the given formula value. The SectorId is exposed as a property, which makes it really nice for dealing with web drop downs, etc. When you save, you'll still need to bind the "real" association. Assuming that SectorId was selected in a form...

using (var txn = session.BeginTransaction()) {
  // Set the FK reference.
  company.Sector = session.Load<Sector>(company.SectorId);
  // Save the new record.
  session.Save(company);
  // Commit the transaction.
  txn.Commit();
}

这篇关于流利的NHibernate - 如何将外键列映射为一个属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆