【问题标题】:Let 2 different mapping files work with same domain让 2 个不同的映射文件使用同一个域
【发布时间】:2011-04-04 22:45:10
【问题描述】:

我正在开发的应用程序需要支持 3 个数据库。 Sybase、SQL 和 Oracle。

我们现在遇到了 Oracle 的问题。对于 oracle,我们使用序列作为 id 生成器,对于 Sybase 和 Oracle,我们使用自己的实现来生成 ID。

我们遇到了一个包含双主键的表的问题。我的映射文件包含一个复合 ID。但是在复合 ID 中,您不能使用生成的值。对于 Oracle 和 Sybase,这没有问题,因为我手动创建了新 ID。但是对于 Oracle,我确实有一个问题,因为必须使用序列。

所以我想做的是创建第二个特定于 Oracle 的映射文件,它只使用 1 个字段作为 PK。我的查询不正确,但我没有看到任何其他选项可以这样做..

所以我有 2 个映射文件:

Sybase 和 SQL:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping default-cascade="none" xmlns="urn:nhibernate-mapping-2.2"
    namespace="VS3.Domain.Address" assembly="VS3.Domain">

<class name="Top_Address" table="TOP_ADDRESS">
<composite-id name="ID" class="IDComposite_TopAddress">
  <key-property name="TnrAddress" column="TNR_ADDRESS" type="Int32"/>
  <key-many-to-one name="TopIdentity" class="Top_Identity" column="TNR_ID"/>
</composite-id>

<property name="nmAddress" column="NM_ADDRESS" type="String" not-null="true"/>
<property name="dPosx" column="D_POSX" type="Decimal" not-null="false"/>
<property name="dPosy" column="D_POSY" type="Decimal" not-null="false"/>

<property name="nmStreetAdd" column="NM_STREET_ADD" type="String" not-null="false"/>
<property name="nmStreetAdd2" column="NM_STREET_ADD2" type="String" not-null="false"/>
<property name="nmStreetAdd3" column="NM_STREET_ADD3" type="String" not-null="false"/>

<!-- Added By Transics -->
<property name="HouseNumber" column="CNR_HOUSE_ADD" type="String" not-null="false" />
<property name="BusNumber" column="CNR_BUS_ADD" type="String" not-null="false" />
<property name="PostalCode" column="CNR_ZIP" type="String" not-null="false" />
<property name="City" column="NM_ZIP" type="String" not-null="false" />
<property name="Country" column="COD_COUNTRY" type="String" not-null="false" />
<property name="Email" column="CNR_EMAIL_ADD" type="String" not-null="false" />
<property name="Phone" column="CNR_PHONE_ADD" type="String" not-null="false" />
<property name="CellPhone" column="CNR_GSM_ADD" type="String" not-null="false" />
<property name="NmAddress2" column="NM_ADDRESS2" type="String" not-null="false" />

<property name="Active" column="BOL_ACTIVE_ADD" type="Int32" not-null="false" />
<property name="Language" column="COD_LANG" type="String" not-null="false" />
<property name="AmFrom" column="T_TRB_AM_FROM" type="DateTime" not-null="false" />
<property name="AmUntil" column="T_TRB_AM_UNTIL" type="DateTime" not-null="false" />
<property name="PmFrom" column="T_TRB_PM_FROM" type="DateTime" not-null="false" />
<property name="PmUntil" column="T_TRB_PM_UNTIL" type="DateTime" not-null="false" />
<property name="Remark" column="DES_TRB_REMARK" type="String" not-null="false" />
<property name="ExtraInformation" column="TXT_ADDRESS" type="String" not-null="false" />
<property name="AddressType" column ="COD_ADDRESSTYPE" type="Char" not-null="false" />
<property name="AddressOrPlace" column ="COD_TRB_ADDRESSTYPE" type="String" not-null="false" />

</class>
</hibernate-mapping>

甲骨文:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping default-cascade="none" xmlns="urn:nhibernate-mapping-2.2"
    namespace="VS3.Domain.Address" assembly="VS3.Domain">

<class name="Top_Address_Oracle" table="TOP_ADDRESS">
<id name="TnrAddress" column="TNR_ADDRESS" type="Int32">
  <generator class="sequence" />
</id>

<property name="nmAddress" column="NM_ADDRESS" type="String" not-null="true"/>
<property name="dPosx" column="D_POSX" type="Decimal" not-null="false"/>
<property name="dPosy" column="D_POSY" type="Decimal" not-null="false"/>

<property name="nmStreetAdd" column="NM_STREET_ADD" type="String" not-null="false"/>
<property name="nmStreetAdd2" column="NM_STREET_ADD2" type="String" not-null="false"/>
<property name="nmStreetAdd3" column="NM_STREET_ADD3" type="String" not-null="false"/>
<property name="HouseNumber" column="CNR_HOUSE_ADD" type="String" not-null="false" />
<property name="BusNumber" column="CNR_BUS_ADD" type="String" not-null="false" />
<property name="PostalCode" column="CNR_ZIP" type="String" not-null="false" />
<property name="City" column="NM_ZIP" type="String" not-null="false" />
<property name="Country" column="COD_COUNTRY" type="String" not-null="false" />
<property name="Email" column="CNR_EMAIL_ADD" type="String" not-null="false" />
<property name="Phone" column="CNR_PHONE_ADD" type="String" not-null="false" />
<property name="CellPhone" column="CNR_GSM_ADD" type="String" not-null="false" />
<property name="NmAddress2" column="NM_ADDRESS2" type="String" not-null="false" />

<property name="Active" column="BOL_ACTIVE_ADD" type="Int32" not-null="false" />
<property name="Language" column="COD_LANG" type="String" not-null="false" />
<property name="AmFrom" column="T_TRB_AM_FROM" type="DateTime" not-null="false" />
<property name="AmUntil" column="T_TRB_AM_UNTIL" type="DateTime" not-null="false" />
<property name="PmFrom" column="T_TRB_PM_FROM" type="DateTime" not-null="false" />
<property name="PmUntil" column="T_TRB_PM_UNTIL" type="DateTime" not-null="false" />
<property name="Remark" column="DES_TRB_REMARK" type="String" not-null="false" />
<property name="ExtraInformation" column="TXT_ADDRESS" type="String" not-null="false" />
<property name="AddressType" column ="COD_ADDRESSTYPE" type="Char" not-null="false" />
<property name="AddressOrPlace" column ="COD_TRB_ADDRESSTYPE" type="String" not-null="false" />

<many-to-one name="Identity" class="Identity" column="TNR_ID" not-null="true"/>
</class>
</hibernate-mapping>

有什么方法可以确保这些映射文件使用相同的域类?还是我也需要创建一个新域(就像我目前所做的那样)。

但这并不是一个真正的选择。工作量太大了。

有人对此有解决方案吗?

【问题讨论】:

    标签: c# nhibernate mapping


    【解决方案1】:

    您可以为同一个域类拥有两个映射文件 - 如果您在执行代码期间只需要一个(我假设,因为同时处理两个不同的数据库将是一场噩梦)表和域类)。在创建 SessionFactory 之前,您可以过滤 hbm 文件并根据参数仅获取您想要的文件。

    您需要一个用于 Oracle 的映射文件,另一个用于其余的,例如MyEntity.oracle.hbm.xmlMyEntity.default.hbm.xml。对于那些在两种情况下完全相同的类,您只需将它们保持原样,例如MyCommonEntity.hbm.xml.

    这是我在项目中使用的代码稍作修改的示例。 (我在 SO 上的另一个问题中发布了另一个版本:Dynamically change the id generator to “assigned” in NHibernate class mapping

    private ISessionFactory BuildSessionFactory(bool useOracleMapping)
    {
        Configuration config = new Configuration();
    
        config.SetProperty(NHibernate.Cfg.Environment.ConnectionProvider, "...");
        config.SetProperty(NHibernate.Cfg.Environment.Dialect, "...");
        config.SetProperty(NHibernate.Cfg.Environment.ConnectionDriver, "...");
        config.SetProperty(NHibernate.Cfg.Environment.ConnectionString, "...");
        config.SetProperty(NHibernate.Cfg.Environment.Isolation, "Serializable");
        config.SetProperty(NHibernate.Cfg.Environment.ProxyFactoryFactoryClass, "...");
        config.SetProperty(NHibernate.Cfg.Environment.ShowSql, "true");
        config.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "none");
    
        // filter hbm Files
    
        // Set reference to entity assembly
        System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(MyEntity));
    
        // get Resource-files
        string[] resources = assembly.GetManifestResourceNames();
    
        // scan through all the hbm files and filter them according to the parameter
        foreach (string hbmFile in resources)
        {
            // This filtering here could probably be done simpler, but this is easy to understand
            bool addFile = false;
            // ignore any file that does not end with .hbm.xml
            if (hbmFile.EndsWith(".hbm.xml"))
            {
                if (hbmFile.ToLower().EndsWith(".default.hbm.xml"))
                {
                    if (!useOracleMapping)
                    {
                        // we want that file for this SessionFactory
                        addFile = true;
                    }
                }
                else if (hbmFile.ToLower().EndsWith(".oracle.hbm.xml"))
                {
                    if (useOracleMapping)
                    {
                        // we want that file for this SessionFactory
                        addFile = true;
                    }
                }
                else
                {
                    // neither default nor oracle -> we want that file no matter what
                    addFile = true;
                }
                if (addFile)
                {
                    using (System.IO.StreamReader sr = new System.IO.StreamReader(assembly.GetManifestResourceStream(hbmFile)))
                    {
                        string resourceContent = sr.ReadToEnd();
                        config.AddXmlString(resourceContent);
                    }
                }
            }
        }
    
        // create Sessionfactory with the files we filtered
        ISessionFactory sessionFactory = config.BuildSessionFactory();
        return sessionFactory;
    }
    

    编辑:

    假设无论您是在 Oracle 还是其他模式下,您始终可以访问知识,我将包装 GetTop_AddressById() 方法并执行以下操作:

    public Top_Address GetTop_AddressById(IDComposite_TopAddress id)
    {
        if (!oracle)
        {
            return session.CreateCriteria(DB, typeof(Top_Address))
               .Add(Restrictions.Eq("ID.TnrAddress", addressID))
               .Add(Restrictions.Eq("ID.TopIdentity.tnrId", tnrID))
               .Add(Restrictions.Eq("AddressType", 'R')) .UniqueResult<Top_Address>();
        }
        else 
        {
            return session.CreateCriteria(DB, typeof(Top_Address))
               .Add(Restrictions.Eq("TnrAddress", addressID))
               .Add(Restrictions.Eq("AddressType", 'R')) .UniqueResult<Top_Address>();
        }
    }
    

    这可能不太好,但我认为为同一目的设置两个课程更糟糕。对于所有使用 id 的 CRUD 操作,您将需要一个这样的包装器。当然,您还需要在域类中拥有 TnrAddress 属性。

    【讨论】:

    • 谢谢 :) 这对我有点帮助。在我的域中(如您在我的映射文件中所见),我为 PK 创建了一个类。我的 oracle 映射文件不是这种情况。我正在使用它来检索我的服务中的某些值等等。例如: CreateCriteria(DB, typeof(Top_Address)) .Add(Expression.Eq("ID.TnrAddress", addressID)) .Add(Expression.Eq("ID.TopIdentity.tnrId", tnrID)) .Add(Expression .Eq("AddressType", 'R')) .UniqueResult();如果我在不更改域且仅更改映射的情况下执行此操作,这会起作用吗?
    • 谢谢!也是我想做的,但希望有更好的解决方案..
    【解决方案2】:

    我建议您不要分叉映射,而是: 通过反序列化的映射元数据,在创建 SessionFacorty 之前,添加您需要的修改。我不能给你代码,但在这里你可以抓住这个想法:http://fabiomaulo.blogspot.com/2010/01/map-nhibernate-using-your-api.html

    或者

    创建一个自定义的id生成器,这里里面处理两个key系统的区别: http://nhforge.org/wikis/howtonh/creating-a-custom-id-generator-for-nhibernate.aspx

    【讨论】:

    • 嗨,谢谢你的回答:) 我不能使用第一种方法,因为不是整个应用程序都使用 Nhibernate。我们只将它用于应用程序的一部分。创建自定义 ID 生成器也不起作用,因为在复合 ID 中我无法添加生成的值。
    猜你喜欢
    • 2014-10-01
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 2022-10-23
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多