在我的情況下,我想用一個屬性來表示一個屬性,該屬性應該參與一個多對多的關係,其中只有關係的一方被聲明。你可以很容易地修改這個以按照其他約定映射。
多對多關係由FluentNHibernate.Automapping.Steps.HasManyToManyStep
處理,由DefaultAutomappingConfiguration
返回。如果該步驟發現相關類型的相應屬性,則該步驟將只映射屬性(因此必須聲明多對多關係的兩端)。
我已經採用的方法是:
- 爲
HasManyToManyStep
支持檢測和映射創建裝飾類多對許多基於屬性的存在(或一些其他約定)屬性
- 創建時並覆蓋
GetMappingSteps
從DefaultAutomappingConfiguration
派生的類,包裝的HasManyToManyStep
任何實例與裝飾
這裏的修飾器,它首先嚐試使用默認的HasManyToManyStep
功能。否則,如果爲成員定義HasManyToManyAttribute
,則它也會創建關係。用於創建關係的代碼幾乎與HasManyToManyStep
使用的代碼完全相同 - 只是沒有提到關係的另一方。
class ExplicitHasManyToManyStep : IAutomappingStep
{
readonly IAutomappingConfiguration Configuration;
readonly IAutomappingStep DefaultManyToManyStep;
public ExplicitHasManyToManyStep(IAutomappingConfiguration configuration, IAutomappingStep defaultManyToManyStep)
{
Configuration = configuration;
DefaultManyToManyStep = defaultManyToManyStep;
}
#region Implementation of IAutomappingStep
public bool ShouldMap(Member member)
{
if (DefaultManyToManyStep.ShouldMap(member))
{
return true;
}
//modify this statement to check for other attributes or conventions
return member.MemberInfo.IsDefined(typeof(HasManyToManyAttribute), true);
}
public void Map(ClassMappingBase classMap, Member member)
{
if (DefaultManyToManyStep.ShouldMap(member))
{
DefaultManyToManyStep.Map(classMap, member);
return;
}
var Collection = CreateManyToMany(classMap, member);
classMap.AddCollection(Collection);
}
#endregion
CollectionMapping CreateManyToMany(ClassMappingBase classMap, Member member)
{
var ParentType = classMap.Type;
var ChildType = member.PropertyType.GetGenericArguments()[0];
var Collection = CollectionMapping.For(CollectionTypeResolver.Resolve(member));
Collection.ContainingEntityType = ParentType;
Collection.Set(x => x.Name, Layer.Defaults, member.Name);
Collection.Set(x => x.Relationship, Layer.Defaults, CreateManyToMany(member, ParentType, ChildType));
Collection.Set(x => x.ChildType, Layer.Defaults, ChildType);
Collection.Member = member;
SetDefaultAccess(member, Collection);
SetKey(member, classMap, Collection);
return Collection;
}
void SetDefaultAccess(Member member, CollectionMapping mapping)
{
var ResolvedAccess = MemberAccessResolver.Resolve(member);
if (ResolvedAccess != Access.Property && ResolvedAccess != Access.Unset)
{
mapping.Set(x => x.Access, Layer.Defaults, ResolvedAccess.ToString());
}
if (member.IsProperty && !member.CanWrite)
{
mapping.Set(x => x.Access, Layer.Defaults, Configuration.GetAccessStrategyForReadOnlyProperty(member).ToString());
}
}
static ICollectionRelationshipMapping CreateManyToMany(Member member, Type parentType, Type childType)
{
var ColumnMapping = new ColumnMapping();
ColumnMapping.Set(x => x.Name, Layer.Defaults, childType.Name + "_id");
var Mapping = new ManyToManyMapping {ContainingEntityType = parentType};
Mapping.Set(x => x.Class, Layer.Defaults, new FluentNHibernate.MappingModel.TypeReference(childType));
Mapping.Set(x => x.ParentType, Layer.Defaults, parentType);
Mapping.Set(x => x.ChildType, Layer.Defaults, childType);
Mapping.AddColumn(Layer.Defaults, ColumnMapping);
return Mapping;
}
static void SetKey(Member property, ClassMappingBase classMap, CollectionMapping mapping)
{
var ColumnName = property.DeclaringType.Name + "_id";
var ColumnMapping = new ColumnMapping();
ColumnMapping.Set(x => x.Name, Layer.Defaults, ColumnName);
var Key = new KeyMapping {ContainingEntityType = classMap.Type};
Key.AddColumn(Layer.Defaults, ColumnMapping);
mapping.Set(x => x.Key, Layer.Defaults, Key);
}
}
HasManyToManyAttribute
類,因爲沒有其他約定,我可以很容易地依賴於我的情況:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class HasManyToManyAttribute : Attribute
{
}
配置類從DefaultMappingConfiguration
類派生:
class AutomappingConfiguration : DefaultAutomappingConfiguration
{
public override IEnumerable<IAutomappingStep> GetMappingSteps(AutoMapper mapper, IConventionFinder conventionFinder)
{
return base.GetMappingSteps(mapper, conventionFinder).Select(GetDecoratedStep);
}
IAutomappingStep GetDecoratedStep(IAutomappingStep step)
{
if (step is HasManyToManyStep)
{
return new ExplicitHasManyToManyStep(this, step);
}
return step;
}
}
其繼承策略你使用?每個具體類的表,每個類的表或每個子表的表? – Firo
我不確定,哪一個確切。也許一個例子可以解釋:我有'Event:Entity'映射到名爲'Event'的表,其中包含'Event'和基類'Entity'的所有屬性。 – davehauser
這將是每個具體類的表。我只知道每個子類的Override <>',這不是你想要的或者大量使用反射來調用覆蓋動態過濾類型 – Firo