11namespace DotNetToolkit . Repository . Configuration . Conventions . Internal
22{
3- using Extensions ;
43 using Extensions . Internal ;
54 using JetBrains . Annotations ;
65 using Properties ;
1413
1514 internal class ForeignKeyConventionHelper
1615 {
17- private static readonly ConcurrentDictionary < PropertyInfo , PropertyInfo [ ] > _foreignKeyCache = new ConcurrentDictionary < PropertyInfo , PropertyInfo [ ] > ( ) ;
16+ private static readonly ConcurrentDictionary < PropertyInfo , Result > _foreignKeyCache = new ConcurrentDictionary < PropertyInfo , Result > ( ) ;
1817
19- public static PropertyInfo [ ] GetForeignKeyPropertyInfos ( [ NotNull ] PropertyInfo pi )
18+ public static Result GetForeignKeyPropertyInfos ( [ NotNull ] PropertyInfo pi )
2019 {
2120 Guard . NotNull ( pi , nameof ( pi ) ) ;
22-
23- if ( ! _foreignKeyCache . TryGetValue ( pi , out PropertyInfo [ ] result ) )
21+
22+ if ( ! _foreignKeyCache . TryGetValue ( pi , out var result ) )
2423 {
2524 result = GetForeignKeyPropertyInfosCore ( pi ) ;
2625 _foreignKeyCache . TryAdd ( pi , result ) ;
2726 }
28-
27+
2928 return result ;
3029 }
3130
32- private static PropertyInfo [ ] GetForeignKeyPropertyInfosCore ( PropertyInfo pi )
31+ private static Result GetForeignKeyPropertyInfosCore ( PropertyInfo pi )
3332 {
3433 var foreignType = pi . PropertyType . GetGenericTypeOrDefault ( ) ;
3534 var declaringType = pi . DeclaringType ;
3635
3736 if ( foreignType . IsEnumerable ( ) || declaringType . IsEnumerable ( ) )
38- return new PropertyInfo [ 0 ] ;
37+ return null ;
3938
40- PropertyInfo [ ] propertyInfos = new PropertyInfo [ 0 ] ;
39+ bool foundInSource ;
4140
42- if ( TryGetForeignKeyPropertyInfos ( foreignType , declaringType , out var foreignKeyPropertyInfosFromTarget , out _ ) )
41+ if ( TryGetForeignKeyPropertyInfos ( foreignType , declaringType ,
42+ out var foreignKeyPropertyInfos ,
43+ out var foreignNavPropertyInfo ,
44+ out var adjacentNavPropertyInfo ) )
45+ {
46+ foundInSource = false ;
47+ adjacentNavPropertyInfo = pi ;
48+ }
49+ else if ( TryGetForeignKeyPropertyInfos ( declaringType , foreignType ,
50+ out foreignKeyPropertyInfos ,
51+ out foreignNavPropertyInfo ,
52+ out adjacentNavPropertyInfo ) )
4353 {
44- propertyInfos = foreignKeyPropertyInfosFromTarget ;
54+ foundInSource = true ;
4555 }
46- else if ( TryGetForeignKeyPropertyInfos ( declaringType , foreignType , out _ , out var primaryKeyPropertyInfosFromSource ) )
56+ else
4757 {
48- propertyInfos = primaryKeyPropertyInfosFromSource ;
58+ return null ;
4959 }
5060
51- return propertyInfos ;
61+ var rightNavPi = pi ;
62+ var rightPiType = rightNavPi . PropertyType . GetGenericTypeOrDefault ( ) ;
63+ var rightKeysToJoinOn = foundInSource
64+ ? PrimaryKeyConventionHelper . GetPrimaryKeyPropertyInfos ( rightPiType )
65+ : foreignKeyPropertyInfos ;
66+
67+ var leftNavPi = foreignNavPropertyInfo ;
68+ var leftPiType = leftNavPi . PropertyType . GetGenericTypeOrDefault ( ) ;
69+ var leftKeysToJoinOn = foundInSource
70+ ? foreignKeyPropertyInfos
71+ : PrimaryKeyConventionHelper . GetPrimaryKeyPropertyInfos ( leftPiType ) ;
72+
73+ var newLeftNavPi = foundInSource ? adjacentNavPropertyInfo : leftNavPi ;
74+
75+ return new Result ( newLeftNavPi , leftKeysToJoinOn , rightNavPi , rightKeysToJoinOn ) ;
5276 }
5377
54- private static bool TryGetForeignKeyPropertyInfos ( Type source , Type target , out PropertyInfo [ ] foreignKeyPropertyInfosFromTarget , out PropertyInfo [ ] primaryKeyPropertyInfosFromSource )
78+ private static bool TryGetForeignKeyPropertyInfos ( Type source , Type target ,
79+ out PropertyInfo [ ] foreignKeyPropertyInfos ,
80+ out PropertyInfo foreignNavPropertyInfo ,
81+ out PropertyInfo adjacentNavPropertyInfo )
5582 {
56- var properties = source . GetRuntimeProperties ( ) . Where ( ModelConventionHelper . IsColumnMapped ) . ToList ( ) ;
57- var foreignNavigationPropertyInfo = properties . SingleOrDefault ( x => x . PropertyType == target ) ;
58- var propertyInfos = new List < PropertyInfo > ( ) ;
83+ var propsFromSource = source . GetRuntimeProperties ( ) . Where ( ModelConventionHelper . IsColumnMapped ) . ToList ( ) ;
84+ var propsFromTarget = target . GetRuntimeProperties ( ) . Where ( ModelConventionHelper . IsColumnMapped ) . ToList ( ) ;
85+
86+ var foreignNavPi = propsFromSource . FirstOrDefault ( x => x . PropertyType == target ) ;
87+ var adjacentNavPi = propsFromTarget . FirstOrDefault ( x => x . PropertyType == source ) ;
5988
60- foreignKeyPropertyInfosFromTarget = null ;
61- primaryKeyPropertyInfosFromSource = null ;
89+ var foreignKeyPiList = new List < PropertyInfo > ( ) ;
6290
63- if ( foreignNavigationPropertyInfo != null )
91+ adjacentNavPropertyInfo = null ;
92+ foreignKeyPropertyInfos = null ;
93+ foreignNavPropertyInfo = null ;
94+
95+ if ( foreignNavPi != null )
6496 {
65- // Gets by checking the annotations
66- var propertyInfosWithForeignKeys = properties . Where ( x => x . GetCustomAttribute < ForeignKeyAttribute > ( ) != null ) . ToList ( ) ;
97+ // Gets by checking the annotations in source
98+ var propertyInfosWithForeignKeys = propsFromSource . Where ( x => x . GetCustomAttribute < ForeignKeyAttribute > ( ) != null ) . ToList ( ) ;
6799 if ( propertyInfosWithForeignKeys . Any ( ) )
68100 {
69101 // Ensure that the foreign key names are valid
70102 foreach ( var propertyInfosWithForeignKey in propertyInfosWithForeignKeys )
71103 {
72104 var foreignKeyAttributeName = propertyInfosWithForeignKey . GetCustomAttribute < ForeignKeyAttribute > ( ) . Name ;
73- if ( ! properties . Any ( x => foreignKeyAttributeName . Equals ( ModelConventionHelper . GetColumnName ( x ) ) ) )
105+ if ( ! propsFromSource . Any ( x => foreignKeyAttributeName . Equals ( ModelConventionHelper . GetColumnName ( x ) ) ) )
74106 {
75107 throw new InvalidOperationException (
76108 string . Format (
@@ -82,49 +114,66 @@ private static bool TryGetForeignKeyPropertyInfos(Type source, Type target, out
82114 }
83115
84116 // Try to find by checking on the foreign key property
85- propertyInfos = propertyInfosWithForeignKeys
117+ foreignKeyPiList = propertyInfosWithForeignKeys
86118 . Where ( DotNetToolkit . Repository . Extensions . Internal . PropertyInfoExtensions . IsPrimitive )
87- . Where ( x => x . GetCustomAttribute < ForeignKeyAttribute > ( ) . Name . Equals ( foreignNavigationPropertyInfo . Name ) )
119+ . Where ( x => x . GetCustomAttribute < ForeignKeyAttribute > ( ) . Name . Equals ( foreignNavPi . Name ) )
88120 . ToList ( ) ;
89121
90122 // Try to find by checking on the navigation property
91- if ( ! propertyInfos . Any ( ) )
123+ if ( ! foreignKeyPiList . Any ( ) )
92124 {
93- propertyInfos = properties
125+ foreignKeyPiList = propsFromSource
94126 . Where ( DotNetToolkit . Repository . Extensions . Internal . PropertyInfoExtensions . IsPrimitive )
95- . Where ( x => foreignNavigationPropertyInfo . GetCustomAttribute < ForeignKeyAttribute > ( ) . Name . Equals ( ModelConventionHelper . GetColumnName ( x ) ) )
127+ . Where ( x => foreignNavPi . GetCustomAttribute < ForeignKeyAttribute > ( ) . Name . Equals ( ModelConventionHelper . GetColumnName ( x ) ) )
96128 . ToList ( ) ;
97129 }
98130 }
99131
100132 // Try to find by naming convention
101133 var primaryKeyPropertyInfos = PrimaryKeyConventionHelper . GetPrimaryKeyPropertyInfos ( target ) ;
102134
103- if ( ! propertyInfos . Any ( ) && primaryKeyPropertyInfos . Any ( ) )
135+ if ( ! foreignKeyPiList . Any ( ) && primaryKeyPropertyInfos . Any ( ) )
104136 {
105137 foreach ( var primaryKeyPropertyInfo in primaryKeyPropertyInfos )
106138 {
107139 var foreignPrimaryKeyName = ModelConventionHelper . GetColumnName ( primaryKeyPropertyInfo ) ;
108- var propertyName = $ "{ foreignNavigationPropertyInfo . Name } { foreignPrimaryKeyName } ";
109- var propertyInfo = properties . FirstOrDefault ( x => x . Name == propertyName ) ;
140+ var propertyName = $ "{ foreignNavPi . Name } { foreignPrimaryKeyName } ";
141+ var propertyInfo = propsFromSource . FirstOrDefault ( x => x . Name == propertyName ) ;
110142
111143 if ( propertyInfo != null )
112144 {
113- propertyInfos . Add ( propertyInfo ) ;
145+ foreignKeyPiList . Add ( propertyInfo ) ;
114146 }
115147 }
116148 }
117149
118- if ( propertyInfos . Any ( ) )
150+ if ( foreignKeyPiList . Any ( ) )
119151 {
120- foreignKeyPropertyInfosFromTarget = propertyInfos . ToArray ( ) ;
121- primaryKeyPropertyInfosFromSource = primaryKeyPropertyInfos ;
152+ foreignKeyPropertyInfos = foreignKeyPiList . ToArray ( ) ;
153+ foreignNavPropertyInfo = foreignNavPi ;
154+ adjacentNavPropertyInfo = adjacentNavPi ;
122155
123156 return true ;
124157 }
125158 }
126159
127160 return false ;
128161 }
162+
163+ public class Result
164+ {
165+ public PropertyInfo LeftNavPi { get ; }
166+ public PropertyInfo [ ] LeftKeysToJoinOn { get ; }
167+ public PropertyInfo RightNavPi { get ; }
168+ public PropertyInfo [ ] RightKeysToJoinOn { get ; }
169+
170+ public Result ( PropertyInfo leftNavPi , PropertyInfo [ ] leftKeysToJoinOn , PropertyInfo rightNavPi , PropertyInfo [ ] rightKeysToJoinOn )
171+ {
172+ LeftNavPi = leftNavPi ;
173+ LeftKeysToJoinOn = leftKeysToJoinOn ;
174+ RightNavPi = rightNavPi ;
175+ RightKeysToJoinOn = rightKeysToJoinOn ;
176+ }
177+ }
129178 }
130179}
0 commit comments