Skip to content

Instantly share code, notes, and snippets.

@jogibear9988
Created March 15, 2013 13:30
Show Gist options
  • Save jogibear9988/5169867 to your computer and use it in GitHub Desktop.
Save jogibear9988/5169867 to your computer and use it in GitHub Desktop.
Source/BLToolkit.4.csproj | 2 +
Source/Mapping/Fluent/AssociationMap.cs | 58 ++++++++++++++++++++--
Source/Mapping/Fluent/Attributes.cs | 15 ++++++
Source/Mapping/Fluent/FluentMap.Interface.cs | 23 ++++++++-
Source/Mapping/Fluent/FluentMap.cs | 14 ++++--
Source/Mapping/Fluent/IFluentMap.cs | 4 +-
Source/Mapping/Fluent/MapFieldMap.cs | 12 +++--
Source/Mapping/ObjectMapper.cs | 19 +++++++
Source/Reflection/Extension/TypeExtension.cs | 3 +-
.../MetadataProvider/AttributeMetadataProvider.cs | 22 ++++++++
.../MetadataProvider/ExtensionMetadataProvider.cs | 30 +++++++++++
.../MetadataProvider/LinqMetadataProvider.cs | 2 +-
.../MetadataProvider/MetadataProviderBase.cs | 9 ++++
.../MetadataProvider/MetadataProviderList.cs | 17 +++++++
UnitTests/Fluent/UnitTests.Fluent.csproj | 1 +
15 files changed, 216 insertions(+), 15 deletions(-)
diff --git a/Source/BLToolkit.4.csproj b/Source/BLToolkit.4.csproj
index 4fe53c7..5b2accd 100644
--- a/Source/BLToolkit.4.csproj
+++ b/Source/BLToolkit.4.csproj
@@ -341,6 +341,8 @@
<Compile Include="Data\Sql\SqlValue.cs" />
<Compile Include="Mapping\AssociationAttribute.cs" />
<Compile Include="Mapping\Association.cs" />
+ <Compile Include="Mapping\ManyToManyAssociation.cs" />
+ <Compile Include="Mapping\ManyToManyAssociationAttribute.cs" />
<Compile Include="Mapping\ExpressionMapper.cs" />
<Compile Include="Mapping\Fluent\AssociationMap.cs" />
<Compile Include="Mapping\Fluent\Attributes.cs" />
diff --git a/Source/Mapping/Fluent/AssociationMap.cs b/Source/Mapping/Fluent/AssociationMap.cs
index edfbb06..00f9aa9 100644
--- a/Source/Mapping/Fluent/AssociationMap.cs
+++ b/Source/Mapping/Fluent/AssociationMap.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
+using System.Linq;
+
namespace BLToolkit.Mapping.Fluent
{
@@ -24,14 +26,60 @@ namespace BLToolkit.Mapping.Fluent
var keys = new List<Expression<Func<TRf, TRo>>>(otherKeys);
keys.Insert(0, otherKey);
return this._owner.Association(this._canBeNull, this._thisKeys, keys);
- }
-
- public MapFieldMap<T, TR> ToOne<TRo>(Expression<Func<TR, TRo>> otherKey, params Expression<Func<TR, TRo>>[] otherKeys)
+ }
+
+ public MapFieldMap<T, TR> ToOne<TRo>(Expression<Func<TR, TRo>> otherKey, params Expression<Func<TR, TRo>>[] otherKeys)
{
var keys = new List<Expression<Func<TR, TRo>>>(otherKeys);
keys.Insert(0, otherKey);
return this._owner.Association(this._canBeNull, this._thisKeys, keys);
- }
- }
+ }
+
+
+ #region ManyToMany Relations
+
+ public MapFieldMap<T, TR> ToManyRel<TRf, TRo>(Expression<Func<TRf, TRo>> otherKey)
+ {
+ return ToManyRel(otherKey);
+ }
+
+ public MapFieldMap<T, TR> ToManyRel<TRf, TRo, TRmap, TRthis, TRother>(Expression<Func<TRf, TRo>> otherKey, Expression<Func<TRmap, TRthis>> relThisKey, Expression<Func<TRmap, TRother>> relOtherKey)
+ {
+ return ToManyRel(otherKey, KeysToString(new[] { relThisKey }), KeysToString(new[] { relOtherKey }));
+ }
+
+ public MapFieldMap<T, TR> ToManyRel<TRf, TRo>(Expression<Func<TRf, TRo>> otherKey, string relThisKey = null, string relOtherKey = null, string relTable = null)
+ {
+ var keys = new List<Expression<Func<TRf, TRo>>>();
+ keys.Insert(0, otherKey);
+ return this._owner.ManyToManyAssociation(this._canBeNull, this._thisKeys, keys, relThisKey, relOtherKey, relTable);
+ }
+
+ #endregion
+
+ private const string MemberNameSeparator = ".";
+
+ private string GetExprName<TT, TR>(Expression<Func<TT, TR>> prop)
+ {
+ string result = null;
+ var memberExpression = prop.Body as MemberExpression;
+ while (null != memberExpression)
+ {
+ result = null == result ? "" : MemberNameSeparator + result;
+ result = memberExpression.Member.Name + result;
+ memberExpression = memberExpression.Expression as MemberExpression;
+ }
+ if (null == result)
+ {
+ throw new ArgumentException("Fail member access expression.");
+ }
+ return result;
+ }
+
+ private string KeysToString<T1, T2>(IEnumerable<Expression<Func<T1, T2>>> keys)
+ {
+ return keys.Select(this.GetExprName).Aggregate((s1, s2) => s1 + ", " + s2);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Source/Mapping/Fluent/Attributes.cs b/Source/Mapping/Fluent/Attributes.cs
index ab4fc32..571b72e 100644
--- a/Source/Mapping/Fluent/Attributes.cs
+++ b/Source/Mapping/Fluent/Attributes.cs
@@ -77,6 +77,21 @@
public const string Storage = "Storage";
}
+ public static class ManyToManyAssociation
+ {
+ public const string ThisKey = "ThisKey";
+
+ public const string OtherKey = "OtherKey";
+
+ public const string Storage = "Storage";
+
+ public const string RelationTableThisKey = "RelationTableThisKey";
+
+ public const string RelationTableOtherKey = "RelationTableOtherKey";
+
+ public const string RelationTableName = "RelationTableName";
+ }
+
public const string NonUpdatable = "NonUpdatable";
public const string Identity = "Identity";
diff --git a/Source/Mapping/Fluent/FluentMap.Interface.cs b/Source/Mapping/Fluent/FluentMap.Interface.cs
index 61ecd6c..6f64617 100644
--- a/Source/Mapping/Fluent/FluentMap.Interface.cs
+++ b/Source/Mapping/Fluent/FluentMap.Interface.cs
@@ -278,7 +278,28 @@ namespace BLToolkit.Mapping.Fluent
attributeExtension.Values.Add(Attributes.Association.Storage, this.ToString(canBeNull));
attrs.Add(attributeExtension);
this.EachChilds(m => m.Association(propName, canBeNull, thisKeys, otherKeys));
- }
+ }
+
+ void IFluentMap.ManyToManyAssociation(string propName, bool canBeNull, string thisKeys, string otherKeys, string thisKeysRel, string otherKeysRel, string relTableName)
+ {
+ var member = this.GetMemberExtension(propName);
+ AttributeExtensionCollection attrs;
+ if (!member.Attributes.TryGetValue(TypeExtension.NodeName.ManyToManyAssociation, out attrs))
+ {
+ attrs = new AttributeExtensionCollection();
+ member.Attributes.Add(TypeExtension.NodeName.ManyToManyAssociation, attrs);
+ }
+ attrs.Clear();
+ var attributeExtension = new AttributeExtension();
+ attributeExtension.Values.Add(Attributes.ManyToManyAssociation.ThisKey, thisKeys);
+ attributeExtension.Values.Add(Attributes.ManyToManyAssociation.OtherKey, otherKeys);
+ attributeExtension.Values.Add(Attributes.ManyToManyAssociation.Storage, this.ToString(canBeNull));
+ attributeExtension.Values.Add(Attributes.ManyToManyAssociation.RelationTableThisKey, thisKeysRel);
+ attributeExtension.Values.Add(Attributes.ManyToManyAssociation.RelationTableOtherKey, thisKeysRel);
+ attributeExtension.Values.Add(Attributes.ManyToManyAssociation.RelationTableName, relTableName);
+ attrs.Add(attributeExtension);
+ this.EachChilds(m => m.Association(propName, canBeNull, thisKeys, otherKeys));
+ }
/// <summary>
/// Relations the specified prop name.
diff --git a/Source/Mapping/Fluent/FluentMap.cs b/Source/Mapping/Fluent/FluentMap.cs
index 7308d2b..36d2361 100644
--- a/Source/Mapping/Fluent/FluentMap.cs
+++ b/Source/Mapping/Fluent/FluentMap.cs
@@ -343,9 +343,17 @@ namespace BLToolkit.Mapping.Fluent
string name = this.GetExprName(prop);
((IFluentMap)this).Association(name, canBeNull, this.KeysToString(thisKeys.ToArray()), this.KeysToString(otherKeys.ToArray()));
return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop);
- }
-
- /// <summary>
+ }
+
+ protected MapFieldMap<T, TR> ManyToManyAssociation<TRt, TR, TRf, TRo>(Expression<Func<T, TR>> prop, bool canBeNull
+ , IEnumerable<Expression<Func<T, TRt>>> thisKeys, IEnumerable<Expression<Func<TRf, TRo>>> otherKeys, string relThisKey, string relOtherKey, string relTable)
+ {
+ string name = this.GetExprName(prop);
+ ((IFluentMap)this).ManyToManyAssociation(name, canBeNull, this.KeysToString(thisKeys.ToArray()), this.KeysToString(otherKeys.ToArray()), relThisKey, relOtherKey, relTable);
+ return new MapFieldMap<T, TR>(this._typeExtension, this.Childs, prop);
+ }
+
+ /// <summary>
/// Reverse on BLToolkit.Mapping.Association.ParseKeys()
/// </summary>
/// <typeparam name="T1"></typeparam>
diff --git a/Source/Mapping/Fluent/IFluentMap.cs b/Source/Mapping/Fluent/IFluentMap.cs
index b3d2ba8..f5a4076 100644
--- a/Source/Mapping/Fluent/IFluentMap.cs
+++ b/Source/Mapping/Fluent/IFluentMap.cs
@@ -155,7 +155,9 @@ namespace BLToolkit.Mapping.Fluent
/// <param name="canBeNull">if set to <c>true</c> [can be null].</param>
/// <param name="thisKeys">The this keys.</param>
/// <param name="otherKeys">The other keys.</param>
- void Association(string propName, bool canBeNull, string thisKeys, string otherKeys);
+ void Association(string propName, bool canBeNull, string thisKeys, string otherKeys);
+
+ void ManyToManyAssociation(string propName, bool canBeNull, string thisKeys, string otherKeys, string thisKeysRel, string otherKeysRel, string relTable);
/// <summary>
/// Relations the specified prop name.
diff --git a/Source/Mapping/Fluent/MapFieldMap.cs b/Source/Mapping/Fluent/MapFieldMap.cs
index 577734c..0fc6f33 100644
--- a/Source/Mapping/Fluent/MapFieldMap.cs
+++ b/Source/Mapping/Fluent/MapFieldMap.cs
@@ -185,9 +185,15 @@ namespace BLToolkit.Mapping.Fluent
, IEnumerable<Expression<Func<T, TRt>>> thisKeys, IEnumerable<Expression<Func<TRf, TRo>>> otherKeys)
{
return this.Association(this._prop, canBeNull, thisKeys, otherKeys);
- }
-
- /// <summary>
+ }
+
+ private MapFieldMap<T, TR> ManyToManyAssociation<TRt, TRf, TRo>(bool canBeNull
+ , IEnumerable<Expression<Func<T, TRt>>> thisKeys, IEnumerable<Expression<Func<TRf, TRo>>> otherKeys, string relThisKey, string relOtherKey, string relTable)
+ {
+ return this.ManyToManyAssociation(this._prop, canBeNull, thisKeys, otherKeys, relThisKey, relOtherKey, relTable);
+ }
+
+ /// <summary>
/// RelationAttribute
/// </summary>
/// <param name="slaveIndex"></param>
diff --git a/Source/Mapping/ObjectMapper.cs b/Source/Mapping/ObjectMapper.cs
index 97549a1..1ace202 100644
--- a/Source/Mapping/ObjectMapper.cs
+++ b/Source/Mapping/ObjectMapper.cs
@@ -112,6 +112,12 @@ namespace BLToolkit.Mapping
get { return _associations; }
}
+ readonly List<ManyToManyAssociation> _manyToManyAssociations = new List<ManyToManyAssociation>();
+ public List<ManyToManyAssociation> ManyToManyAssociations
+ {
+ get { return _manyToManyAssociations; }
+ }
+
readonly List<InheritanceMappingAttribute> _inheritanceMapping = new List<InheritanceMappingAttribute>();
public List<InheritanceMappingAttribute> InheritanceMapping
{
@@ -259,6 +265,14 @@ namespace BLToolkit.Mapping
continue;
}
+ var b = this.GetManyToManyAssociation(ma);
+
+ if (b != null)
+ {
+ _manyToManyAssociations.Add(b);
+ continue;
+ }
+
if (GetMapIgnore(ma))
continue;
@@ -564,6 +578,11 @@ namespace BLToolkit.Mapping
return MetadataProvider.GetAssociation(Extension, memberAccessor);
}
+ protected virtual ManyToManyAssociation GetManyToManyAssociation(MemberAccessor memberAccessor)
+ {
+ return MetadataProvider.GetManyToManyAssociation(Extension, memberAccessor);
+ }
+
protected virtual InheritanceMappingAttribute[] GetInheritanceMapping()
{
return MetadataProvider.GetInheritanceMapping(_typeAccessor.OriginalType, Extension);
diff --git a/Source/Reflection/Extension/TypeExtension.cs b/Source/Reflection/Extension/TypeExtension.cs
index ed5c4d2..fdc3864 100644
--- a/Source/Reflection/Extension/TypeExtension.cs
+++ b/Source/Reflection/Extension/TypeExtension.cs
@@ -16,7 +16,8 @@ namespace BLToolkit.Reflection.Extension
public const string Type = "Type";
public const string Member = "Member";
public const string Association = "Association";
- public const string Relation = "Relation";
+ public const string ManyToManyAssociation = "ManyToManyAssociation";
+ public const string Relation = "Relation";
public const string MasterIndex = "MasterIndex";
public const string SlaveIndex = "SlaveIndex";
}
diff --git a/Source/Reflection/MetadataProvider/AttributeMetadataProvider.cs b/Source/Reflection/MetadataProvider/AttributeMetadataProvider.cs
index b55e9b4..96787e4 100644
--- a/Source/Reflection/MetadataProvider/AttributeMetadataProvider.cs
+++ b/Source/Reflection/MetadataProvider/AttributeMetadataProvider.cs
@@ -682,6 +682,28 @@ namespace BLToolkit.Reflection.MetadataProvider
#endregion
+ #region GetManyToManyAssociation
+
+ public override ManyToManyAssociation GetManyToManyAssociation(TypeExtension typeExtension, MemberAccessor member)
+ {
+ var aa = member.GetAttribute<ManyToManyAssociationAttribute>();
+
+ if (aa == null)
+ return base.GetManyToManyAssociation(typeExtension, member);
+
+ return new ManyToManyAssociation(
+ member,
+ aa.GetThisKeys(),
+ aa.GetOtherKeys(),
+ aa.Storage,
+ aa.CanBeNull,
+ aa.GetRelationTableThisKeys(),
+ aa.GetRelationTableOtherKeys(),
+ aa.RelationTableName);
+ }
+
+ #endregion
+
#region GetInheritanceMapping
public override InheritanceMappingAttribute[] GetInheritanceMapping(Type type, TypeExtension typeExtension)
diff --git a/Source/Reflection/MetadataProvider/ExtensionMetadataProvider.cs b/Source/Reflection/MetadataProvider/ExtensionMetadataProvider.cs
index f9f93a9..2d2b439 100644
--- a/Source/Reflection/MetadataProvider/ExtensionMetadataProvider.cs
+++ b/Source/Reflection/MetadataProvider/ExtensionMetadataProvider.cs
@@ -511,6 +511,36 @@ namespace BLToolkit.Reflection.MetadataProvider
#endregion
+ #region GetManyToManyAssociation
+
+ public override ManyToManyAssociation GetManyToManyAssociation(TypeExtension typeExtension, MemberAccessor member)
+ {
+ if (typeExtension == TypeExtension.Null)
+ return null;
+
+ var mex = typeExtension[member.Name];
+
+ if (mex == MemberExtension.Null)
+ return null;
+
+ var attrs = mex.Attributes[TypeExtension.NodeName.Association];
+
+ if (attrs == AttributeExtensionCollection.Null)
+ return null;
+
+ return new ManyToManyAssociation(
+ member,
+ Association.ParseKeys(attrs[0]["ThisKey", string.Empty].ToString()),
+ Association.ParseKeys(attrs[0]["OtherKey", string.Empty].ToString()),
+ attrs[0]["Storage", string.Empty].ToString(),
+ TypeExtension.ToBoolean(attrs[0]["Storage", "True"], true),
+ Association.ParseKeys(attrs[0]["RelThisKey", string.Empty].ToString()),
+ Association.ParseKeys(attrs[0]["RelOtherKey", string.Empty].ToString()),
+ attrs[0]["RelTableName", string.Empty].ToString());
+ }
+
+ #endregion
+
#region GetInheritanceMapping
public override InheritanceMappingAttribute[] GetInheritanceMapping(Type type, TypeExtension typeExtension)
diff --git a/Source/Reflection/MetadataProvider/LinqMetadataProvider.cs b/Source/Reflection/MetadataProvider/LinqMetadataProvider.cs
index 2fc3bb3..210130f 100644
--- a/Source/Reflection/MetadataProvider/LinqMetadataProvider.cs
+++ b/Source/Reflection/MetadataProvider/LinqMetadataProvider.cs
@@ -219,7 +219,7 @@ namespace BLToolkit.Reflection.MetadataProvider
#endregion
- #region GetInheritanceMapping
+ #region GetInheritanceMapping
public override InheritanceMappingAttribute[] GetInheritanceMapping(Type type,TypeExtension typeExtension)
{
diff --git a/Source/Reflection/MetadataProvider/MetadataProviderBase.cs b/Source/Reflection/MetadataProvider/MetadataProviderBase.cs
index d27d66a..06384c4 100644
--- a/Source/Reflection/MetadataProvider/MetadataProviderBase.cs
+++ b/Source/Reflection/MetadataProvider/MetadataProviderBase.cs
@@ -267,6 +267,15 @@ namespace BLToolkit.Reflection.MetadataProvider
#endregion
+ #region GetManyToManyAssociation
+
+ public virtual ManyToManyAssociation GetManyToManyAssociation(TypeExtension typeExtension, MemberAccessor member)
+ {
+ return null;
+ }
+
+ #endregion
+
#region GetInheritanceMapping
public virtual InheritanceMappingAttribute[] GetInheritanceMapping(Type type, TypeExtension typeExtension)
diff --git a/Source/Reflection/MetadataProvider/MetadataProviderList.cs b/Source/Reflection/MetadataProvider/MetadataProviderList.cs
index c6d4f76..9184337 100644
--- a/Source/Reflection/MetadataProvider/MetadataProviderList.cs
+++ b/Source/Reflection/MetadataProvider/MetadataProviderList.cs
@@ -371,6 +371,23 @@ namespace BLToolkit.Reflection.MetadataProvider
#endregion
+ #region GetAssociation
+
+ public override ManyToManyAssociation GetManyToManyAssociation(TypeExtension typeExtension, MemberAccessor member)
+ {
+ foreach (var p in _list)
+ {
+ var attr = p.GetManyToManyAssociation(typeExtension, member);
+
+ if (attr != null)
+ return attr;
+ }
+
+ return base.GetManyToManyAssociation(typeExtension, member);
+ }
+
+ #endregion
+
#region GetInheritanceMapping
public override InheritanceMappingAttribute[] GetInheritanceMapping(Type type, TypeExtension typeExtension)
diff --git a/UnitTests/Fluent/UnitTests.Fluent.csproj b/UnitTests/Fluent/UnitTests.Fluent.csproj
index edd72c6..6aaf486 100644
--- a/UnitTests/Fluent/UnitTests.Fluent.csproj
+++ b/UnitTests/Fluent/UnitTests.Fluent.csproj
@@ -49,6 +49,7 @@
<ItemGroup>
<Compile Include="AssertExceptionEx.cs" />
<Compile Include="FluentMapAttributesTest.cs" />
+ <Compile Include="FluentMapManyToManyTest.cs" />
<Compile Include="FluentConfigTest.cs" />
<Compile Include="FluentMapTest.cs" />
<Compile Include="MockDataBase\AssertCommandData.cs" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment