Использование NHibernate с моделью данных EAV
Я пытаюсь использовать NH для сопоставления с моделью данных, которая является свободной интерпретацией модели данных EAV/CR.
У меня большая часть работы, но я борюсь с отображением коллекции Entity.Attributes.
Вот таблицы, о которых идет речь:
--------------------
| Entities |
--------------------
| EntityId PK |-|
| EntityType | |
-------------------- |
-------------
|
V
--------------------
| EntityAttributes | ------------------ ---------------------------
-------------------- | Attributes | | StringAttributes |
| EntityId PK,FK | ------------------ ---------------------------
| AttributeId FK | -> | AttributeId PK | -> | StringAttributeId PK,FK |
| AttributeValue | | AttributeType | | AttributeName |
-------------------- ------------------ ---------------------------
Столбец AttributeValue реализован как столбец sql_variant, и я применил для него NHibernate.UserTypes.IUserType.
Я могу создать объект EntityAttribute и сохранить его напрямую, чтобы работала часть иерархии.
Я просто не уверен, как сопоставить коллекцию EntityAttributes с сущностью Entity.
Обратите внимание: таблица EntityAttributes может (и имеет) содержать несколько строк для данной комбинации EntityId/AttributeId:
EntityId AttributeId AttributeValue
-------- ----------- --------------
1 1 Blue
1 1 Green
Строка StringAttributes выглядит следующим образом:
StringAttributeId AttributeName
----------------- --------------
1 FavoriteColor
Как я могу эффективно сопоставить эту модель данных с моим доменом Entity, чтобы Entity.Attributes( "FavoriteColors" ) возвращал коллекцию любимых цветов? Набирается как System.String?
Ответы
Ответ 1
здесь идет
class Entity
{
public virtual int Id { get; set; }
internal protected virtual ICollection<EntityAttribute> AttributesInternal { get; set; }
public IEnumerable<T> Attributes<T>(string attributeName)
{
return AttributesInternal
.Where(x => x.Attribute.Name == attributeName)
.Select(x => x.Value)
.Cast<T>();
}
}
class EntityAttribute
{
public virtual Attribute Attribute { get; set; }
public virtual object Value { get; set; }
}
class EntityMap : ClassMap<Entity>
{
public EntityMap()
{
HasMany(e => e.AttributesInternal)
.Table("EntityAttributes")
.KeyColumn("EntityId")
// EntityAttribute cant be an Entity because there is no real Primary Key
// (EntityId, [AttributeId] is not unique)
.Component(c =>
{
c.References(ea => ea.Attribute, "AttributeId").Not.LazyLoad();
c.Map(ea => ea.Value, "AttributeValue").CustomType<VariantUserType>();
});
}
}