NHibernate动态列号

War*_*sMe 4 c# sql nhibernate dynamic

在我的C#项目中,我需要在代码中创建一个数据库,其中一个表具有动态列号.像这样

------------------------------------------------------------------------------     
| Time        ¦ Element #1       | Element#2        ¦ ... ¦ Element#N        ¦
------------------------------------------------------------------------------
¦ TimeValue#1 ¦ Element#1Value#1 ¦ Element#2Value#1 ¦ ... ¦ Element#NValue#1 ¦
¦ TimeValue#2 ¦ Element#1Value#2 ¦ Element#2Value#2 ¦ ... ¦ Element#NValue#2 ¦
                                      ...
¦ TimeValue#M ¦ Element#1Value#M ¦ Element#2Value#M ¦ ... ¦ Element#NValue#M ¦
------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

我使用简单的SQL查询'SQL CREATE TABLE'

public void AddTable(string TableName, Dictionary<string,Type> columns)
{        
    ...
    string query = @"CREATE TABLE " + TableName + "(";

    foreach (var c in columns)
    {
        SqlParameter temp = new SqlParameter();
        string t = SetSQLType(ref temp, c.Value).ToString();
        query += c.Key + " " + (t == SqlDbType.NVarChar.ToString() ? (t + "(200)") : (t)) + ",";
    }

    query = query.Substring(0, query.Length - 1);
    query += " )";
    ...
}
Run Code Online (Sandbox Code Playgroud)

但我想,也许,我可以使用更舒适的ORM,例如 - NHibernate.我可以吗?我读到了关于代码和动态组件的映射,但我不确定,在我的情况下我到底需要做什么.

我想,我需要这样的事情:

public class Elements
{
    public virtual DateTime Timestamp { get; set; }
    public virtual IEnumerable<double> Values { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我可以映射这个类吗?

Rad*_*ler 9

这个主题很有趣.初看起来也许不那么清楚.将我的答案作为概述,来自下面列出的所有来源的摘要.也许它会给你答案.

从C#的角度来看,您可以通过这种方式考虑这些动态属性

public virtual IDictionary<keyType, valueType> Additional { get; set; } 
                 // (e.g. <string, object>

public virtual IDictionary Additional { get; set; }
Run Code Online (Sandbox Code Playgroud)

这两者都是动态的.没有编译时检查处理IDictionary.更好的情况是通用参数检查IDictinary<,>.但是因为我们在讨论动态映射,所以我们可以牺牲编译时检查...

要将数据加载到其中一个词典中,我们必须(在大多数情况下)执行不同的映射并具有不同的表结构.Generic对于转换行中包含的数据非常方便.Non-Generic可用于映射(作为问题中的示例).我们来讨论两者

1)Generic IDictionary<,>- 动态行

让我们从更安全的场景开始吧.然后触摸解决方案接近问题

1a)三元协会

例如,让我们根据角色/类型将一些人映射到某个实体(例如合同).1)经理2)领导者3)测试员.如果我们知道每个类型/角色只有一个人(只有一个测试人员或者没有),我们可以解释为:

public virtual IDictionary<PersonType, Person> Persons { get; set; }
Run Code Online (Sandbox Code Playgroud)

我们现在充满活力.可能有0,1或1个人与合同有关.他们每个人都必须是独一无二的PersonType.我们还可以PersonType在运行时引入新的s,并扩展任何Contract的相关Person集......

映射应该是这样的

<map name="Persons" table="ContractPerson" >
    <key column="ContractId"/>
     <index-many-to-many column="PersonTypeId" class="PersonType"/>
     <one-to-many class="Person"/>
</map>
Run Code Online (Sandbox Code Playgroud)

这是6.9的一个例子.三元协会.涉及三个实体,我们仍然在运行时具有灵活性.如前所述,我们可以插入新的PersonTypes并修改这些Contract-Person关系.

这种情况(与之相比IDictiniary<string, object>)仍然提供了大量的编译时检查.

1b)更接近问题

在上面描述的场景中,如果我们想<map>行的角度使用和动态- 我们需要一个这样的表:

ElemntId| TheKey       | TheValue (e.g. nvarchar)
1       | "name"       | "Element A"
1       | "time"       | "20:02"
1       | "date"       | "2013-05-22"
1       | "value"      | "11.22"
Run Code Online (Sandbox Code Playgroud)

C#看起来像这样

public class Elements
{
    ...
    public virtual IDictionary<string, string> Values { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

制图:

<map name="Values" table="DynamicElementValues" >
   <key column="ElementId"/>
    <index column="TheKey" type="string"/>
    <element column="TheValue" type="string"/>
</map>
Run Code Online (Sandbox Code Playgroud)

因为我们使用的IDictionary<string, string>所有值都是字符串.我们需要一些MetaData人正确地解释它的价值

我们获得了:

  • 动态收集许多类型的许多值

我们失去了:

  • 能够将任何值放入SELECT或ORDER BY子句中
  • 必须转换数据类型(从字符串转换为任何其他)

1c)键作为 string

实际上,带string密钥的字典是动态的,但是太多了.如1a)所示,总是更好的想法,以某种方式管理要用作密钥的值集.这就是我们讨论三元协会的原因.因为我们迟早要解释这个字典中的数据 - 使用一些MetaData,将它们作为关键字使用它们也很方便...

2)非通用IDictionary- 动态

这次我们将真正尝试对列进行动态解决方案.

NHibernate的功能,我们可以在这里使用:

根据我们的要求,这种映射非常接近问题.我们将有这个C#表示

public class Elements
{
    ...
    public virtual IDictionary DynamicValues { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这可能是映射:

<join table="ElemntValues" >

  <key column="ElementId" />
  <dynamic-component name="DynamicValues"   >

    <property name="Time"        type="TimeSpan" />
    <property name="Date"        type="DateTime" />
    <property name="Salary"      type="decimal" />
    <property name="Color"       type="string" />
    <property name="WorkingDays" type="integer"  />
    <many-to one....
    ...

  </dynamic-component>
</join>
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们确实有separted表ElementValues,加入我们的Parent实体(作为其<class>映射的一部分).

这不是唯一的映射.可能存在其他映射类型,例如4.4.动态模型

<class entity-name="DynamicValues"...
Run Code Online (Sandbox Code Playgroud)

这些可能需要一些更特殊的处理(插入,udpate,删除)

加入会简化很多东西,但总会在SQL语句中使用(即使只需要核心属性)

它是动态的吗?

我们获得了:

  • 在C#上我们只有属性 IDictionary ElementValues
  • NHibernate为我们运行时检查.只能将正确类型的值插入到键中(工资必须为十进制)
  • 对于某些MetaData模型,我们可以真正地为用户提供动态
  • 任何Mapped属性都可用于SELECT(投影)和ORDER BY(用户会喜欢它)

我们失去了:

  • 一些性能,因为将加载所有数据(例如session.Get <>(id))
  • 在添加或删除列的情况下,我们不是动态的.所有映射都是应用程序分发的一部分,并且不能在运行时更改.好吧,我们总是可以重新部署新的映射......

2b)IDictionary和MetaData

虽然IDictinary从C#透视图非常动态(它可能包含任何键/对值),但由于NHibernate映射,内容被管理.只能将integer值添加到映射为的属性中 integer.但是我们如何在运行时知道:我们拥有哪些键?什么价值可以放在那里并从那里检索?同样,我们需要一些MetaData ......不能充当密钥的角色,但它们在运行时是至关重要的.NHibernate检查是最后一道防线.

3)如何在运行时更改映射(添加新列)?

那么,文档中说明了什么?7.5.动态组件:

这种映射的优点是能够在部署时确定组件的实际属性,只需编辑映射文档即可.(使用DOM解析器也可以对映射文档进行运行时操作.)

...使用DOM解析器.说实话,我不知道这是什么意思,如何实现.

还有Adam Bar在" 按代码映射 - 动态组件"中的说明(见评论)

我认为动态组件在对象和数据库级别都不是真正的动态.请注意,组件部分存储为普通列,因此我们需要知道它的列表...

但是Firo 有一个很好的想法- NHibernate动态映射(看看,对于某些提取来说太复杂了).如果真的需要,这可能是一个真正的动态世界的解决方案...运行时的新列...新的键映射IDictionary

摘要

通过<map>映射,我们可以非常动态.运行时中的不同键和值.无需重新部署.但是我们不能在select或order by中使用这些动态属性.这些值很难过滤

随着<dynamic-component>我们(开箱即用)依赖于映射.但是我们确实在列中有数据,因此我们可以使用连接来检索它们.易于过滤,排序.和/但必须有一些metadata指导我们我们拥有的和我们能做的.

其他来源: