我需要对具有复合主键的表使用Fluent-nHibernate(Azure表,主键是(PartitionKey,RowKey),我想将它们映射到实体上的相应属性(或使用组件属性,如果更容易)
我的桌子看起来像是:
{
PartitionKey PK,
RowKey PK,
[..]
}
和实体
public class MyRecord
{
public virtual string PartitionKey{get;set;}
public virtual string RowKey{get;set;}
[...]
}
我目前的项目使用针对AzureTable的自定义nHibernate驱动程序。
我设法使其适用于ClassMap或XML映射。因此我确信司机正在工作。此外,使用类映射或XML声明,azure表HTTP请求是正确的。
但是我确实需要约定,所以这不是一个可接受的解决方案。
最后,总是可以选择仅将RowKey映射为PK,即使数据存储区使用(PartitionKey,RowKey)也是如此。它也可以工作,但它并不令人满意,因为它引入了nHibernate与底层数据存储区之间处理不匹配的单一性。
更新
我试图建立一个自定义的IIdentityConvention。 IIdentityInstance.Column()方法仅考虑第一次调用。 但是,如果我使用反射将两列添加到基础映射字段,则配置构建将失败,并带有XML验证异常(需要属性'class')
答案 0 :(得分:1)
我今天得到了它,但它并不漂亮。它也没有使用惯例。据我了解惯例,它们真正意味着在主映射发生后调整事物。我认为添加映射被认为超出了约定的范围。
在我的项目中,我有一个基于自动化的通用初始化过程,它不知道任何类型,但具有依赖注入的映射覆盖复合键。不完全是您的情况,但这是一个类似的问题。
我通过反射工作的方式是获取适当的AutoPersistenceModel对象。如果您的代码如下所示:
Fluently.Configure().Mappings(m => ...
AutoPersistenceModel对象将是m.AutoMappings.First()
从这里开始,它是非常严肃的反射工作,最终在FluentNHibernate中调用受保护的方法。这是我正在使用的代码:
private void Override(AutoPersistenceModel container,
Type type,
IEnumerable<KeyValuePair<string,string>> compositeKeys)
{
// We need to call container.Override<T>(Action<Automapping<T>> populateMap)
// Through reflection...yikes
var overrideMethod = typeof(AutoPersistenceModel)
.GetMethod("Override")
.MakeGenericMethod(type);
var actionFactoryMethod = typeof(FluentNHibernateInitializer)
.GetMethod("CompositeMapperFactory",
BindingFlags.Instance | BindingFlags.NonPublic)
.MakeGenericMethod(type);
var actionMethod = actionFactoryMethod
.Invoke(this, new object[] { compositeKeys });
overrideMethod.Invoke(container, new object[] {actionMethod});
}
private Action<AutoMapping<T>> CompositeMapperFactory<T>
(IEnumerable<KeyValuePair<string, string>> compositeKeys)
{
return new Action<AutoMapping<T>>(m =>
{
var compositeId = m.CompositeId();
foreach (var kvp in compositeKeys)
compositeId =
AddKeyProperty(
compositeId,
typeof(T).GetProperty(kvp.Key),
kvp.Value);
}
);
}
/// <summary>
/// Uses reflection to invoke private and protected members!
/// </summary>
/// <param name="compositeId"></param>
/// <param name="propertyInfo"></param>
/// <returns></returns>
private CompositeIdentityPart<T> AddKeyProperty<T>
(CompositeIdentityPart<T> compositeId,
PropertyInfo propertyInfo,
string column)
{
var member = FluentNHibernate.MemberExtensions.ToMember(propertyInfo);
var keyPropertyMethod = typeof(CompositeIdentityPart<T>)
.GetMethod("KeyProperty",
BindingFlags.Instance | BindingFlags.NonPublic);
return (CompositeIdentityPart<T>)
keyPropertyMethod
.Invoke(compositeId, new object[] { member, column, null });
}