From bf12431a924b5e63ff3acf7e6bfeb1551734d749 Mon Sep 17 00:00:00 2001 From: ToddThomson Date: Thu, 23 Aug 2018 13:05:39 -0700 Subject: [PATCH] Progress towards lazy loading: Unified member accessors. --- Achilles.Entities.Sqlite/DataContext.cs | 2 +- .../{ => Linq}/EntityCollectionOfT.cs | 2 +- .../{ => Linq}/EntityReferenceOfT.cs | 10 +- .../{ => Linq}/IEntityCollection.cs | 2 +- .../{ => Linq}/IEntityCollectionOfT.cs | 2 +- .../{ => Linq}/IEntityReference.cs | 2 +- .../{ => Linq}/IEntityReferenceOfT.cs | 2 +- .../Mapping/Builders/HasManyMappingBuilder.cs | 1 + .../Mapping/Builders/HasOneMappingBuilder.cs | 1 + .../Modelling/Mapping/ColumnAccessor.cs | 98 +++++++++++++++++++ .../Modelling/Mapping/EntityMapping.cs | 83 +++------------- .../Mapping/EntityMappingCollection.cs | 93 +++++++++--------- .../Modelling/Mapping/IColumnMapping.cs | 2 +- .../Modelling/Mapping/IEntityMapping.cs | 4 +- .../Modelling/Mapping/MemberAccessor.cs | 32 ++++++ .../Querying/EntityMaterializer.cs | 11 +-- .../Delete/DeleteStatementBuilder.cs | 2 +- .../ColumnParameterCollectionBuilder.cs | 2 +- .../Update/ColumnSetCollectionBuilder.cs | 2 +- .../Update/UpdateStatementBuilder.cs | 2 +- Entities.Sqlite.Tests/Data/Customer.cs | 1 + Entities.Sqlite.Tests/Data/Order.cs | 1 + Entities.Sqlite.Tests/Data/Product.cs | 1 + .../Mapping/EntityMappingTest.cs | 6 +- 24 files changed, 226 insertions(+), 138 deletions(-) rename Achilles.Entities.Sqlite/{ => Linq}/EntityCollectionOfT.cs (98%) rename Achilles.Entities.Sqlite/{ => Linq}/EntityReferenceOfT.cs (80%) rename Achilles.Entities.Sqlite/{ => Linq}/IEntityCollection.cs (92%) rename Achilles.Entities.Sqlite/{ => Linq}/IEntityCollectionOfT.cs (93%) rename Achilles.Entities.Sqlite/{ => Linq}/IEntityReference.cs (94%) rename Achilles.Entities.Sqlite/{ => Linq}/IEntityReferenceOfT.cs (93%) create mode 100644 Achilles.Entities.Sqlite/Modelling/Mapping/ColumnAccessor.cs create mode 100644 Achilles.Entities.Sqlite/Modelling/Mapping/MemberAccessor.cs diff --git a/Achilles.Entities.Sqlite/DataContext.cs b/Achilles.Entities.Sqlite/DataContext.cs index 0c0465f..746fbf7 100644 --- a/Achilles.Entities.Sqlite/DataContext.cs +++ b/Achilles.Entities.Sqlite/DataContext.cs @@ -200,7 +200,7 @@ public int Add( TEntity entity ) where TEntity : class // TJT: Sqlite specific var rowId = Database.Connection.LastInsertRowId(); - entityMapping.SetPropertyValue( entity, key.PropertyName, rowId ); + entityMapping.SetColumn( entity, key.PropertyName, rowId ); } return result; diff --git a/Achilles.Entities.Sqlite/EntityCollectionOfT.cs b/Achilles.Entities.Sqlite/Linq/EntityCollectionOfT.cs similarity index 98% rename from Achilles.Entities.Sqlite/EntityCollectionOfT.cs rename to Achilles.Entities.Sqlite/Linq/EntityCollectionOfT.cs index dfd7ea8..886c644 100644 --- a/Achilles.Entities.Sqlite/EntityCollectionOfT.cs +++ b/Achilles.Entities.Sqlite/Linq/EntityCollectionOfT.cs @@ -17,7 +17,7 @@ #endregion -namespace Achilles.Entities +namespace Achilles.Entities.Linq { public sealed class EntityCollection : IEntityCollection, IEntityCollection, ICollection, IListSource where TEntity : class diff --git a/Achilles.Entities.Sqlite/EntityReferenceOfT.cs b/Achilles.Entities.Sqlite/Linq/EntityReferenceOfT.cs similarity index 80% rename from Achilles.Entities.Sqlite/EntityReferenceOfT.cs rename to Achilles.Entities.Sqlite/Linq/EntityReferenceOfT.cs index 3c168c4..b15d7b3 100644 --- a/Achilles.Entities.Sqlite/EntityReferenceOfT.cs +++ b/Achilles.Entities.Sqlite/Linq/EntityReferenceOfT.cs @@ -11,10 +11,11 @@ #region Namespaces using System.Collections.Generic; +using System.Linq; #endregion -namespace Achilles.Entities +namespace Achilles.Entities.Linq { public sealed class EntityReference : IEntityReference, IEntityReference where TEntity : class @@ -53,6 +54,7 @@ public TEntity Entity } } + // TJT: Make a direct internal property (Source) reference through a compiled lambda expression public void AttachSource( IEnumerable source ) { _source = source; @@ -64,7 +66,11 @@ public void AttachSource( IEnumerable source ) private void Load() { - + if ( !_isLoaded && _source != null ) + { + _entity = Enumerable.SingleOrDefault( _source ); + _isLoaded = true; + } } #endregion diff --git a/Achilles.Entities.Sqlite/IEntityCollection.cs b/Achilles.Entities.Sqlite/Linq/IEntityCollection.cs similarity index 92% rename from Achilles.Entities.Sqlite/IEntityCollection.cs rename to Achilles.Entities.Sqlite/Linq/IEntityCollection.cs index 76de6f0..49c1e8f 100644 --- a/Achilles.Entities.Sqlite/IEntityCollection.cs +++ b/Achilles.Entities.Sqlite/Linq/IEntityCollection.cs @@ -8,7 +8,7 @@ #endregion -namespace Achilles.Entities +namespace Achilles.Entities.Linq { /// /// Marker interface diff --git a/Achilles.Entities.Sqlite/IEntityCollectionOfT.cs b/Achilles.Entities.Sqlite/Linq/IEntityCollectionOfT.cs similarity index 93% rename from Achilles.Entities.Sqlite/IEntityCollectionOfT.cs rename to Achilles.Entities.Sqlite/Linq/IEntityCollectionOfT.cs index 7c84c47..5d67251 100644 --- a/Achilles.Entities.Sqlite/IEntityCollectionOfT.cs +++ b/Achilles.Entities.Sqlite/Linq/IEntityCollectionOfT.cs @@ -14,7 +14,7 @@ #endregion -namespace Achilles.Entities +namespace Achilles.Entities.Linq { internal interface IEntityCollection { diff --git a/Achilles.Entities.Sqlite/IEntityReference.cs b/Achilles.Entities.Sqlite/Linq/IEntityReference.cs similarity index 94% rename from Achilles.Entities.Sqlite/IEntityReference.cs rename to Achilles.Entities.Sqlite/Linq/IEntityReference.cs index 0633d49..3910da2 100644 --- a/Achilles.Entities.Sqlite/IEntityReference.cs +++ b/Achilles.Entities.Sqlite/Linq/IEntityReference.cs @@ -10,7 +10,7 @@ using System.Collections.Generic; -namespace Achilles.Entities +namespace Achilles.Entities.Linq { /// /// Marker interface diff --git a/Achilles.Entities.Sqlite/IEntityReferenceOfT.cs b/Achilles.Entities.Sqlite/Linq/IEntityReferenceOfT.cs similarity index 93% rename from Achilles.Entities.Sqlite/IEntityReferenceOfT.cs rename to Achilles.Entities.Sqlite/Linq/IEntityReferenceOfT.cs index 3317521..b512c28 100644 --- a/Achilles.Entities.Sqlite/IEntityReferenceOfT.cs +++ b/Achilles.Entities.Sqlite/Linq/IEntityReferenceOfT.cs @@ -8,7 +8,7 @@ #endregion -namespace Achilles.Entities +namespace Achilles.Entities.Linq { public interface IEntityReference { diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/HasManyMappingBuilder.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/HasManyMappingBuilder.cs index 05c8711..63d0ee5 100644 --- a/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/HasManyMappingBuilder.cs +++ b/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/HasManyMappingBuilder.cs @@ -11,6 +11,7 @@ #region Namespaces using Achilles.Entities.Extensions; +using Achilles.Entities.Linq; using Achilles.Entities.Reflection; using System; using System.Linq.Expressions; diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/HasOneMappingBuilder.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/HasOneMappingBuilder.cs index 9ad7f67..9b1a75a 100644 --- a/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/HasOneMappingBuilder.cs +++ b/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/HasOneMappingBuilder.cs @@ -11,6 +11,7 @@ #region Namespaces using Achilles.Entities.Extensions; +using Achilles.Entities.Linq; using Achilles.Entities.Reflection; using System; using System.Collections; diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/ColumnAccessor.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/ColumnAccessor.cs new file mode 100644 index 0000000..1a7738d --- /dev/null +++ b/Achilles.Entities.Sqlite/Modelling/Mapping/ColumnAccessor.cs @@ -0,0 +1,98 @@ +#region Copyright Notice + +// Copyright (c) by Achilles Software, All rights reserved. +// +// Licensed under the MIT License. See License.txt in the project root for license information. +// +// Send questions regarding this copyright notice to: mailto:todd.thomson@achilles-software.com + +#endregion + +#region Namespaces + +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +#endregion + +namespace Achilles.Entities.Modelling.Mapping +{ + internal class ColumnAccessor : MemberAccessor + where TEntity : class + { + private readonly MemberInfo _columnInfo; + + private Func _getter; + private Action _setter; + + public ColumnAccessor( MemberInfo columnInfo ) + : base( columnInfo ) + { + _columnInfo = columnInfo; + + CreateGetter(); + CreateSetter(); + } + + public override object GetValue( TMember entity ) => _getter( entity as TEntity ); + + public override void SetValue( TMember entity, object value ) => _setter( entity as TEntity, value ); + + private void CreateGetter() + { + if ( _columnInfo is PropertyInfo propertyInfo ) + { + ParameterExpression instance = Expression.Parameter( typeof( TEntity ), "instance" ); + + var body = Expression.Call( instance, propertyInfo.GetGetMethod() ); + var parameters = new ParameterExpression[] { instance }; + Expression conversion = Expression.Convert( body, typeof( object ) ); + + _getter = Expression.Lambda>( conversion, parameters ).Compile(); + } + else if ( _columnInfo is FieldInfo field ) + { + ParameterExpression instance = Expression.Parameter( typeof( TEntity ), "instance" ); + + MemberExpression fieldExpression = Expression.Field( instance, field ); + var parameters = new ParameterExpression[] { instance }; + Expression conversion = Expression.Convert( fieldExpression, typeof( object ) ); + + _getter = Expression.Lambda>( conversion, parameters ).Compile(); + } + } + + private void CreateSetter() + { + if ( _columnInfo is PropertyInfo propertyInfo ) + { + var columnPropertySetMethod = propertyInfo.GetSetMethod(); + var setMethodParameterType = columnPropertySetMethod.GetParameters().First().ParameterType; + + var entityInstanceParameter = Expression.Parameter( typeof( TEntity ), "instance" ); + var valueParameter = Expression.Parameter( typeof( object ), "value" ); + Expression conversion = Expression.Convert( valueParameter, setMethodParameterType ); + + var body = Expression.Call( entityInstanceParameter, columnPropertySetMethod, conversion ); + var parameters = new ParameterExpression[] { entityInstanceParameter, valueParameter }; + + _setter = Expression.Lambda>( + body, parameters ).Compile(); + } + else if ( _columnInfo is FieldInfo field ) + { + var instanceParameter = Expression.Parameter( typeof( TEntity ), "instance" ); + var valueParameter = Expression.Parameter( typeof( object ), "value" ); + Expression conversion = Expression.Convert( valueParameter, field.FieldType ); + + MemberExpression fieldExpression = Expression.Field( instanceParameter, field ); + BinaryExpression assignExp = Expression.Assign( fieldExpression, conversion ); + + _setter = Expression.Lambda>( + assignExp, instanceParameter, valueParameter ).Compile(); + } + } + } +} diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMapping.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMapping.cs index 2da01bc..8e755bf 100644 --- a/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMapping.cs +++ b/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMapping.cs @@ -29,10 +29,14 @@ public class EntityMapping : IEntityMapping where TEntity : class { #region Fields - private Dictionary _columnMapping; + private Dictionary _columnProperties; + private Dictionary _foreignKeyProperties; + private Dictionary _relationshipProperties; - private Dictionary> Getters = new Dictionary>(); - private Dictionary> Setters = new Dictionary>(); + //private Dictionary> ColumnGetters = new Dictionary>(); + //private Dictionary> ColumnSetters = new Dictionary>(); + + private Dictionary ColumnAccessors = new Dictionary(); #endregion @@ -50,9 +54,9 @@ public EntityMapping() #region Public Properties - public object GetPropertyValue( T entity, string propertyName ) where T : class => Getters[ propertyName ].Invoke( entity as TEntity ); + public object GetColumn( T entity, string propertyName ) where T : class => ColumnAccessors[ propertyName ].GetValue( entity as TEntity ); - public void SetPropertyValue( T entity, string propertyName, object value ) where T: class => Setters[ propertyName ].Invoke( entity as TEntity, value ); + public void SetColumn( T entity, string propertyName, object value ) where T: class => ColumnAccessors[ propertyName ].SetValue( entity as TEntity, value ); public List ColumnMappings { get; set; } = new List(); @@ -76,82 +80,27 @@ public EntityMapping() public void Compile() { - _columnMapping = ColumnMappings.ToDictionary( m => m.ColumnName, m => m.ColumnInfo, IsCaseSensitive? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase ); + _columnProperties = ColumnMappings.ToDictionary( m => m.ColumnName, m => m.ColumnInfo, IsCaseSensitive? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase ); - CreateGetters(); - CreateSetters(); + CreateAccessors(); } #endregion #region Private Methods - private void CreateGetters() + private void CreateAccessors() { + // Columns... foreach ( var columnMapping in ColumnMappings ) { - if ( columnMapping.ColumnInfo is PropertyInfo propertyInfo ) - { - ParameterExpression instance = Expression.Parameter( typeof( TEntity ), "instance" ); - - var body = Expression.Call( instance, propertyInfo.GetGetMethod() ); - var parameters = new ParameterExpression[] { instance }; - Expression conversion = Expression.Convert( body, typeof( object ) ); - - var getter = Expression.Lambda>( conversion, parameters ).Compile(); - - Getters.Add( propertyInfo.Name, getter ); - } - else if ( columnMapping.ColumnInfo is FieldInfo field ) - { - ParameterExpression instance = Expression.Parameter( typeof( TEntity ), "instance" ); - - MemberExpression fieldExpression = Expression.Field( instance, field ); - var parameters = new ParameterExpression[] { instance }; - Expression conversion = Expression.Convert( fieldExpression, typeof( object ) ); - - var getter = Expression.Lambda>( conversion, parameters ).Compile(); - - Getters.Add( field.Name, getter ); - } + ColumnAccessors.Add( columnMapping.PropertyName, new ColumnAccessor( columnMapping.ColumnInfo ) ); } } - private void CreateSetters() - { - foreach ( var columnMapping in ColumnMappings ) - { - if ( columnMapping.ColumnInfo is PropertyInfo propertyInfo ) - { - var setMethod = propertyInfo.GetSetMethod(); - var setMethodParameterType = setMethod.GetParameters().First().ParameterType; - - ParameterExpression instance = Expression.Parameter( typeof( TEntity ), "instance" ); - var parameterExpression = Expression.Parameter( typeof( object ), "value" ); - Expression conversion = Expression.Convert( parameterExpression, setMethodParameterType ); - - var body = Expression.Call( instance, setMethod, conversion ); - var parameters = new ParameterExpression[] { instance, parameterExpression }; - var setter = Expression.Lambda>( body, parameters ).Compile(); - - Setters.Add( propertyInfo.Name, setter ); - } - else if ( columnMapping.ColumnInfo is FieldInfo field ) - { - ParameterExpression instance = Expression.Parameter( typeof( TEntity ), "instance" ); - ParameterExpression valueExpression = Expression.Parameter( typeof( object ), "value" ); - Expression conversion = Expression.Convert( valueExpression, field.FieldType ); - - MemberExpression fieldExpression = Expression.Field( instance, field ); - BinaryExpression assignExp = Expression.Assign( fieldExpression, conversion ); - - var setter = Expression.Lambda> - ( assignExp, instance, valueExpression ).Compile(); - - Setters.Add( field.Name, setter ); - } - } + private void CreateRelationshipSetters() + { } /// diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMappingCollection.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMappingCollection.cs index 6aa1292..7c3ebfb 100644 --- a/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMappingCollection.cs +++ b/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMappingCollection.cs @@ -37,9 +37,7 @@ public class EntityMappingCollection //: IDictionary /// public IEntityMapping GetOrAddEntityMapping( Type entityType ) { - IEntityMapping mapping; - - if ( !_entityMappings.TryGetValue( entityType, out mapping ) ) + if ( !_entityMappings.TryGetValue( entityType, out IEntityMapping mapping ) ) { var EntityMappingType = typeof( EntityMapping<> ); var mappingType = EntityMappingType.MakeGenericType( entityType ); @@ -48,6 +46,7 @@ public IEntityMapping GetOrAddEntityMapping( Type entityType ) _entityMappings[ entityType ] = mapping; + // TJT: Review. Perhaps this is better done elsewhere mapping.Compile(); } @@ -73,68 +72,68 @@ public IEntityMapping GetEntityMapping( Type entityType ) throw new ArgumentException( nameof( entityType ) ); } - #region IDictionary Implementation through _EntityMappingpings + //#region IDictionary Implementation through _EntityMappingpings - public IEntityMapping this[ Type key ] { get => ((IDictionary)_entityMappings)[ key ]; set => ((IDictionary)_entityMappings)[ key ] = value; } + //public IEntityMapping this[ Type key ] { get => ((IDictionary)_entityMappings)[ key ]; set => ((IDictionary)_entityMappings)[ key ] = value; } public ICollection Keys => ((IDictionary)_entityMappings).Keys; public ICollection Values => ((IDictionary)_entityMappings).Values; - public int Count => ((IDictionary)_entityMappings).Count; + //public int Count => ((IDictionary)_entityMappings).Count; - public bool IsReadOnly => ((IDictionary)_entityMappings).IsReadOnly; + //public bool IsReadOnly => ((IDictionary)_entityMappings).IsReadOnly; - public void Add( KeyValuePair item ) - { - ((IDictionary)_entityMappings).Add( item ); - } - - public void Clear() - { - ((IDictionary)_entityMappings).Clear(); - } + //public void Add( KeyValuePair item ) + //{ + // ((IDictionary)_entityMappings).Add( item ); + //} - public bool Contains( KeyValuePair item ) - { - return ((IDictionary)_entityMappings).Contains( item ); - } + //public void Clear() + //{ + // ((IDictionary)_entityMappings).Clear(); + //} - public bool ContainsKey( Type key ) - { - return ((IDictionary)_entityMappings).ContainsKey( key ); - } + //public bool Contains( KeyValuePair item ) + //{ + // return ((IDictionary)_entityMappings).Contains( item ); + //} - public void CopyTo( KeyValuePair[] array, int arrayIndex ) - { - ((IDictionary)_entityMappings).CopyTo( array, arrayIndex ); - } + //public bool ContainsKey( Type key ) + //{ + // return ((IDictionary)_entityMappings).ContainsKey( key ); + //} - public IEnumerator> GetEnumerator() - { - return ((IDictionary)_entityMappings).GetEnumerator(); - } + //public void CopyTo( KeyValuePair[] array, int arrayIndex ) + //{ + // ((IDictionary)_entityMappings).CopyTo( array, arrayIndex ); + //} - public bool Remove( Type key ) - { - return ((IDictionary)_entityMappings).Remove( key ); - } + //public IEnumerator> GetEnumerator() + //{ + // return ((IDictionary)_entityMappings).GetEnumerator(); + //} - public bool Remove( KeyValuePair item ) - { - return ((IDictionary)_entityMappings).Remove( item ); - } + //public bool Remove( Type key ) + //{ + // return ((IDictionary)_entityMappings).Remove( key ); + //} - public bool TryGetValue( Type key, out IEntityMapping value ) - { - return ((IDictionary)_entityMappings).TryGetValue( key, out value ); - } + //public bool Remove( KeyValuePair item ) + //{ + // return ((IDictionary)_entityMappings).Remove( item ); + //} - //IEnumerator IEnumerable.GetEnumerator() + //public bool TryGetValue( Type key, out IEntityMapping value ) //{ - // return ((IDictionary)_entityMappings).GetEnumerator(); + // return ((IDictionary)_entityMappings).TryGetValue( key, out value ); //} - #endregion + ////IEnumerator IEnumerable.GetEnumerator() + ////{ + //// return ((IDictionary)_entityMappings).GetEnumerator(); + ////} + + //#endregion } } diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/IColumnMapping.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/IColumnMapping.cs index c292d59..5d3f13e 100644 --- a/Achilles.Entities.Sqlite/Modelling/Mapping/IColumnMapping.cs +++ b/Achilles.Entities.Sqlite/Modelling/Mapping/IColumnMapping.cs @@ -18,7 +18,7 @@ namespace Achilles.Entities.Modelling.Mapping { /// - /// Represents an entity column mapping. + /// Represents an entity property or field to database column mapping. /// public interface IColumnMapping { diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/IEntityMapping.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/IEntityMapping.cs index cf5a613..ec474f6 100644 --- a/Achilles.Entities.Sqlite/Modelling/Mapping/IEntityMapping.cs +++ b/Achilles.Entities.Sqlite/Modelling/Mapping/IEntityMapping.cs @@ -38,9 +38,9 @@ public interface IEntityMapping /// bool IsCaseSensitive { get; set; } - object GetPropertyValue( T entity, string propertyName ) where T : class ; + object GetColumn( T entity, string propertyName ) where T : class ; - void SetPropertyValue( T entity, string propertyName, object value ) where T : class; + void SetColumn( T entity, string propertyName, object value ) where T : class; void Compile(); } diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/MemberAccessor.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/MemberAccessor.cs new file mode 100644 index 0000000..c2d71b0 --- /dev/null +++ b/Achilles.Entities.Sqlite/Modelling/Mapping/MemberAccessor.cs @@ -0,0 +1,32 @@ +#region Copyright Notice + +// Copyright (c) by Achilles Software, All rights reserved. +// +// Licensed under the MIT License. See License.txt in the project root for license information. +// +// Send questions regarding this copyright notice to: mailto:todd.thomson@achilles-software.com + +#endregion + +#region Namespaces + +using System.Reflection; + +#endregion + +namespace Achilles.Entities.Modelling.Mapping +{ + public abstract class MemberAccessor + { + public MemberAccessor( MemberInfo memberInfo ) + { + MemberInfo = memberInfo ?? throw new System.ArgumentNullException( nameof( memberInfo ) ); + } + + protected MemberInfo MemberInfo { get; } + + public abstract object GetValue( TMember member ); + + public abstract void SetValue( TMember member, object value ); + } +} diff --git a/Achilles.Entities.Sqlite/Querying/EntityMaterializer.cs b/Achilles.Entities.Sqlite/Querying/EntityMaterializer.cs index ffb61ba..33a8f49 100644 --- a/Achilles.Entities.Sqlite/Querying/EntityMaterializer.cs +++ b/Achilles.Entities.Sqlite/Querying/EntityMaterializer.cs @@ -10,7 +10,6 @@ #region Namespaces -using Achilles.Entities.Extensions; using Achilles.Entities.Modelling; using Achilles.Entities.Querying.TypeConverters; using System; @@ -170,7 +169,7 @@ internal object Materialize( IDictionary dictionary, object enti { if ( relationshipMapping.IsMany ) { - IEntityCollection entityCollection = memberInfo as IEntityCollection; + //IEntityCollection entityCollection = memberInfo as IEntityCollection; } else { @@ -183,6 +182,7 @@ internal object Materialize( IDictionary dictionary, object enti { PropertyInfo propertyInfo = memberInfo as PropertyInfo; + // Gets the property EntityReference class instance entityReferenceProperty = propertyInfo.GetValue( entity ); } else @@ -193,15 +193,14 @@ internal object Materialize( IDictionary dictionary, object enti } Type entityReferencePropertyType = entityReferenceProperty.GetType(); - MethodInfo methodOfMainProperty = entityReferencePropertyType.GetMethod( "AttachSource" ); + + MethodInfo attachSourceMethod = entityReferencePropertyType.GetMethod( "AttachSource" ); // Get the EntitySet var entityReference = entityReferencePropertyType.GetGenericArguments().First(); - // Get the EntitySet from the foreign key type var entitySet = _context.EntitySets[ entityReference ]; - methodOfMainProperty.Invoke( entityReferenceProperty, new object[] { entitySet } ); - + attachSourceMethod.Invoke( entityReferenceProperty, new object[] { entitySet } ); } continue; diff --git a/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Delete/DeleteStatementBuilder.cs b/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Delete/DeleteStatementBuilder.cs index 1a9870f..6980e64 100644 --- a/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Delete/DeleteStatementBuilder.cs +++ b/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Delete/DeleteStatementBuilder.cs @@ -28,7 +28,7 @@ public DeleteStatement BuildStatement() var keyMembers = _entityMapping.ColumnMappings.Where( p => p.IsKey ).ToList(); var pk = keyMembers.First(); - var pkValue = _entityMapping.GetPropertyValue( _entity, pk.PropertyName ); + var pkValue = _entityMapping.GetColumn( _entity, pk.PropertyName ); var pkParameter = _parameters.Add( pkValue ); diff --git a/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Insert/ColumnParameterCollectionBuilder.cs b/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Insert/ColumnParameterCollectionBuilder.cs index 539ded2..0350c52 100644 --- a/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Insert/ColumnParameterCollectionBuilder.cs +++ b/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Insert/ColumnParameterCollectionBuilder.cs @@ -36,7 +36,7 @@ private IEnumerable CreateColumnParameterStatements() { foreach ( var property in Properties ) { - var propertyValue = _entityMapping.GetPropertyValue( _entity, property.PropertyName ); + var propertyValue = _entityMapping.GetColumn( _entity, property.PropertyName ); var propertyParameter = Parameters.Add( propertyValue ); diff --git a/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Update/ColumnSetCollectionBuilder.cs b/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Update/ColumnSetCollectionBuilder.cs index 87c08af..54ff3f1 100644 --- a/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Update/ColumnSetCollectionBuilder.cs +++ b/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Update/ColumnSetCollectionBuilder.cs @@ -38,7 +38,7 @@ private IEnumerable CreateColumnSetStatements() { foreach ( var property in Properties ) { - var propertyValue = _entityMapping.GetPropertyValue( _entity, property.PropertyName ); + var propertyValue = _entityMapping.GetColumn( _entity, property.PropertyName ); var propertyParameter = Parameters.Add( propertyValue ); diff --git a/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Update/UpdateStatementBuilder.cs b/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Update/UpdateStatementBuilder.cs index 9f8279b..213135f 100644 --- a/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Update/UpdateStatementBuilder.cs +++ b/Achilles.Entities.Sqlite/Sqlite/SqlStatements/Update/UpdateStatementBuilder.cs @@ -34,7 +34,7 @@ public UpdateStatement BuildStatement() var keyMembers = _entityMapping.ColumnMappings.Where( p => p.IsKey ).ToList(); var pk = keyMembers.First(); - var pkValue = _entityMapping.GetPropertyValue( _entity, pk.PropertyName ); + var pkValue = _entityMapping.GetColumn( _entity, pk.PropertyName ); var pkParameter = _parameters.Add( pkValue ); diff --git a/Entities.Sqlite.Tests/Data/Customer.cs b/Entities.Sqlite.Tests/Data/Customer.cs index e5460d3..ece8062 100644 --- a/Entities.Sqlite.Tests/Data/Customer.cs +++ b/Entities.Sqlite.Tests/Data/Customer.cs @@ -1,4 +1,5 @@ using Achilles.Entities; +using Achilles.Entities.Linq; using System.Collections.Generic; namespace Entities.Sqlite.Tests.Data diff --git a/Entities.Sqlite.Tests/Data/Order.cs b/Entities.Sqlite.Tests/Data/Order.cs index da2af9e..e111a29 100644 --- a/Entities.Sqlite.Tests/Data/Order.cs +++ b/Entities.Sqlite.Tests/Data/Order.cs @@ -1,4 +1,5 @@ using Achilles.Entities; +using Achilles.Entities.Linq; using System.Collections.Generic; namespace Entities.Sqlite.Tests.Data diff --git a/Entities.Sqlite.Tests/Data/Product.cs b/Entities.Sqlite.Tests/Data/Product.cs index e53fc27..7794bfc 100644 --- a/Entities.Sqlite.Tests/Data/Product.cs +++ b/Entities.Sqlite.Tests/Data/Product.cs @@ -1,4 +1,5 @@ using Achilles.Entities; +using Achilles.Entities.Linq; namespace Entities.Sqlite.Tests.Data { diff --git a/Entities.Sqlite.Tests/Mapping/EntityMappingTest.cs b/Entities.Sqlite.Tests/Mapping/EntityMappingTest.cs index bd3d789..012f9fd 100644 --- a/Entities.Sqlite.Tests/Mapping/EntityMappingTest.cs +++ b/Entities.Sqlite.Tests/Mapping/EntityMappingTest.cs @@ -69,11 +69,11 @@ public void Mapping_can_get_set_property_value() Country = "Canada" }; - var country = addressEntityMapping.GetPropertyValue( testAddress, "Country" ); + var country = addressEntityMapping.GetColumn( testAddress, "Country" ); Assert.Equal( "Canada", country ); - addressEntityMapping.SetPropertyValue( testAddress, "Country", "USA" ); - var newCountry = addressEntityMapping.GetPropertyValue( testAddress, "Country" ); + addressEntityMapping.SetColumn( testAddress, "Country", "USA" ); + var newCountry = addressEntityMapping.GetColumn( testAddress, "Country" ); Assert.Equal( "USA", newCountry ); }