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)
我可以映射这个类吗?
这个主题很有趣.初看起来也许不那么清楚.将我的答案作为概述,来自下面列出的所有来源的摘要.也许它会给你答案.
从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可用于列映射(作为问题中的示例).我们来讨论两者
IDictionary<,>- 动态行让我们从更安全的场景开始吧.然后触摸解决方案接近问题
例如,让我们根据角色/类型将一些人映射到某个实体(例如合同).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>)仍然提供了大量的编译时检查.
在上面描述的场景中,如果我们想<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人正确地解释它的价值
我们获得了:
我们失去了:
string实际上,带
string密钥的字典是动态的,但是太多了.如1a)所示,总是更好的想法,以某种方式管理要用作密钥的值集.这就是我们讨论三元协会的原因.因为我们迟早要解释这个字典中的数据 - 使用一些MetaData,将它们作为关键字使用它们也很方便...
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语句中使用(即使只需要父核心属性)
它是动态的吗?
我们获得了:
IDictionary ElementValues MetaData模型,我们可以真正地为用户提供动态我们失去了:
虽然
IDictinary从C#透视图非常动态(它可能包含任何键/对值),但由于NHibernate映射,内容被管理.只能将integer值添加到映射为的属性中integer.但是我们如何在运行时知道:我们拥有哪些键?什么价值可以放在那里并从那里检索?同样,我们需要一些MetaData ......不能充当密钥的角色,但它们在运行时是至关重要的.NHibernate检查是最后一道防线.
那么,文档中说明了什么?7.5.动态组件:
这种映射的优点是能够在部署时确定组件的实际属性,只需编辑映射文档即可.(使用DOM解析器也可以对映射文档进行运行时操作.)
...使用DOM解析器.说实话,我不知道这是什么意思,如何实现.
还有Adam Bar在" 按代码映射 - 动态组件"中的说明(见评论)
我认为动态组件在对象和数据库级别都不是真正的动态.请注意,组件部分存储为普通列,因此我们需要知道它的列表...
但是Firo 有一个很好的想法- NHibernate动态映射(看看,对于某些提取来说太复杂了).如果真的需要,这可能是一个真正的动态世界的解决方案...运行时的新列...新的键映射IDictionary
通过<map>映射,我们可以非常动态.运行时中的不同键和值.无需重新部署.但是我们不能在select或order by中使用这些动态属性.这些值很难过滤
随着<dynamic-component>我们(开箱即用)依赖于映射.但是我们确实在列中有数据,因此我们可以使用连接来检索它们.易于过滤,排序.和/但必须有一些metadata指导我们我们拥有的和我们能做的.