diff --git a/Achilles.Entities.Sqlite/IEntitySet.cs b/Achilles.Entities.Sqlite/IEntitySet.cs
index b7e6f45..6fe8518 100644
--- a/Achilles.Entities.Sqlite/IEntitySet.cs
+++ b/Achilles.Entities.Sqlite/IEntitySet.cs
@@ -29,6 +29,6 @@ public interface IEntitySet
///
Type EntityType { get; }
- IEnumerable GetSource( TSource source ) where TSource : class;
+ //IEnumerable GetSource( TSource source ) where TSource : class;
}
}
diff --git a/Achilles.Entities.Sqlite/Linq/EntityReferenceOfT.cs b/Achilles.Entities.Sqlite/Linq/EntityReferenceOfT.cs
index b15d7b3..11ff013 100644
--- a/Achilles.Entities.Sqlite/Linq/EntityReferenceOfT.cs
+++ b/Achilles.Entities.Sqlite/Linq/EntityReferenceOfT.cs
@@ -17,7 +17,7 @@
namespace Achilles.Entities.Linq
{
- public sealed class EntityReference : IEntityReference, IEntityReference
+ public sealed class EntityReference : IEntityReference, IEntityReference, IEntityReferenceSource
where TEntity : class
{
#region Private Fields
@@ -40,6 +40,8 @@ public EntityReference()
#region Public API
+ public bool IsLoaded => _isLoaded;
+
public TEntity Entity
{
get
@@ -54,10 +56,11 @@ public TEntity Entity
}
}
- // TJT: Make a direct internal property (Source) reference through a compiled lambda expression
- public void AttachSource( IEnumerable source )
+ public bool HasSource => (_source != null);
+
+ public void SetSource( IEnumerable source ) where TSource : class
{
- _source = source;
+ _source = source as IEnumerable;
}
#endregion
diff --git a/Achilles.Entities.Sqlite/Linq/IEntityReference.cs b/Achilles.Entities.Sqlite/Linq/IEntityReference.cs
index 3910da2..cd05bf4 100644
--- a/Achilles.Entities.Sqlite/Linq/IEntityReference.cs
+++ b/Achilles.Entities.Sqlite/Linq/IEntityReference.cs
@@ -8,8 +8,6 @@
#endregion
-using System.Collections.Generic;
-
namespace Achilles.Entities.Linq
{
///
@@ -17,6 +15,6 @@ namespace Achilles.Entities.Linq
///
internal interface IEntityReference
{
- //void AttachSource( IEnumerable source ) where TEntityRef: class;
+ // No API
}
}
diff --git a/Achilles.Entities.Sqlite/Linq/IEntityReferenceOfT.cs b/Achilles.Entities.Sqlite/Linq/IEntityReferenceOfT.cs
index b512c28..abc44da 100644
--- a/Achilles.Entities.Sqlite/Linq/IEntityReferenceOfT.cs
+++ b/Achilles.Entities.Sqlite/Linq/IEntityReferenceOfT.cs
@@ -10,7 +10,7 @@
namespace Achilles.Entities.Linq
{
- public interface IEntityReference
+ public interface IEntityReference where TEntity : class
{
///
/// Gets the wrapped entity.
diff --git a/Achilles.Entities.Sqlite/Linq/IEntityReferenceSource.cs b/Achilles.Entities.Sqlite/Linq/IEntityReferenceSource.cs
new file mode 100644
index 0000000..600b566
--- /dev/null
+++ b/Achilles.Entities.Sqlite/Linq/IEntityReferenceSource.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Achilles.Entities.Linq
+{
+ internal interface IEntityReferenceSource
+ {
+ bool HasSource { get; }
+
+ void SetSource( IEnumerable source ) where TSource : class;
+ }
+}
diff --git a/Achilles.Entities.Sqlite/Modelling/EntityModel.cs b/Achilles.Entities.Sqlite/Modelling/EntityModel.cs
index dccf1d5..9f05e44 100644
--- a/Achilles.Entities.Sqlite/Modelling/EntityModel.cs
+++ b/Achilles.Entities.Sqlite/Modelling/EntityModel.cs
@@ -22,47 +22,47 @@ public class EntityModel : IEntityModel
{
#region Private Fields
- private readonly EntityMappingCollection _entityMappings;
+ private DataContext _context;
+ private EntityMappingCollection _entityMappings;
#endregion
#region Constructor(s)
- public EntityModel( EntityMappingCollection entityMappings )
+ public EntityModel( DataContext context )
{
- _entityMappings = entityMappings ?? throw new ArgumentNullException( nameof( entityMappings ) );
+ _context = context;
+ _entityMappings = new EntityMappingCollection( this );
}
#endregion
#region Public API
+ ///
public IReadOnlyCollection EntityMappings => _entityMappings.Values as IReadOnlyCollection;
- //public IEntityMapping GetOrAddEntityMapping( Type entityType )
- //{
- // IEntityMapping mapping;
-
- // if ( !_entityMappings.TryGetValue( entityType, out mapping ) )
- // {
- // var EntityMappingType = typeof( EntityMapping<> );
- // var mapType = EntityMappingType.MakeGenericType( entityType );
-
- // mapping = Activator.CreateInstance( mapType ) as IEntityMapping;
-
- // _entityMappings[ entityType ] = mapping;
- // }
-
- // return mapping;
- //}
-
+ ///
public IEntityMapping GetEntityMapping() where TEntity : class
{
return GetEntityMapping( typeof( TEntity ) );
}
+ ///
public IEntityMapping GetEntityMapping( Type entityType ) => _entityMappings.GetEntityMapping( entityType );
#endregion
+
+ #region Internal
+
+ internal IEntityMapping GetOrAddEntityMapping( Type entityType )
+ => _entityMappings.GetOrAddEntityMapping( entityType );
+
+ internal void TryAddEntityMapping( Type entityType, IEntityMapping entityMapping )
+ => _entityMappings.TryAddEntityMapping( entityType, entityMapping );
+
+ internal DataContext DataContext => _context;
+
+ #endregion
}
}
diff --git a/Achilles.Entities.Sqlite/Modelling/EntityModelBuilder.cs b/Achilles.Entities.Sqlite/Modelling/EntityModelBuilder.cs
index 365abb0..bd0d292 100644
--- a/Achilles.Entities.Sqlite/Modelling/EntityModelBuilder.cs
+++ b/Achilles.Entities.Sqlite/Modelling/EntityModelBuilder.cs
@@ -19,10 +19,12 @@
namespace Achilles.Entities.Modelling
{
///
- /// implementation of the fluent builder inteface for relational database modelling.
+ /// implementation of the fluent builder inteface for entity data modelling.
///
public class EntityModelBuilder : IEntityModelBuilder
{
+ private DataContext _context;
+
#region Constructor(s)
///
@@ -30,15 +32,15 @@ public class EntityModelBuilder : IEntityModelBuilder
///
public EntityModelBuilder()
{
- EntityMappings = new EntityMappingCollection();
}
#endregion
- #region Public Properties
+ #region Private Properties
- ///
- private EntityMappingCollection EntityMappings { get; }
+ private EntityModel Model { get; set; }
+
+ //private EntityMappingCollection EntityMappings => Model.EntityMappings;
#endregion
@@ -47,7 +49,7 @@ public EntityModelBuilder()
///
public void Entity( Action> action ) where TEntity : class
{
- var builder = new EntityMappingBuilder( EntityMappings );
+ var builder = new EntityMappingBuilder( Model );
action( builder );
@@ -57,25 +59,26 @@ public void Entity( Action> action ) whe
///
public IEntityModel Build( DataContext context )
{
+ _context = context;
+
+ Model = new EntityModel( context );
+
// TJT: Should all entities be added in the user's data context constructor?
// What should happen if an entity is referenced during model building that is
// not in the context?
foreach ( var entitySetType in context.EntitySets.Keys )
{
- EntityMappings.GetOrAddEntityMapping( entitySetType );
+ Model.GetOrAddEntityMapping( entitySetType );
}
context.OnModelBuilding( this );
- // TODO: Model Validation...
-
// The model entity mappings have now been configured.
// Resolve Entity references and validate the model.
-
ResolveMappingsAndValidateModel();
- return new EntityModel( EntityMappings );
+ return Model;
}
#endregion
@@ -86,12 +89,18 @@ private void AddEntityMapping( EntityMappingBuilder entityMapp
{
var EntityMapping = entityMappingBuilder.Build();
- EntityMappings.TryAddEntityMapping( typeof( TEntity ), EntityMapping );
+ Model.TryAddEntityMapping( typeof( TEntity ), EntityMapping );
}
private void ResolveMappingsAndValidateModel()
{
+ foreach ( var entityMapping in Model.EntityMappings )
+ {
+ // TJT: Better name?
+ entityMapping.Compile();
+ }
+ // TODO: Model Validation...
}
#endregion
diff --git a/Achilles.Entities.Sqlite/Modelling/IEntityModel.cs b/Achilles.Entities.Sqlite/Modelling/IEntityModel.cs
index 7574fb5..f429388 100644
--- a/Achilles.Entities.Sqlite/Modelling/IEntityModel.cs
+++ b/Achilles.Entities.Sqlite/Modelling/IEntityModel.cs
@@ -26,8 +26,6 @@ public interface IEntityModel
/// A read only collection of .
IReadOnlyCollection EntityMappings { get; }
- //IEntityMapping GetOrAddEntityMapping( Type entityType );
-
///
/// Gets an entity mapping by entity type.
///
@@ -36,7 +34,7 @@ public interface IEntityModel
IEntityMapping GetEntityMapping( Type entityType );
///
- /// TODO
+ /// Gets an entity mapping by the generic TEntity type.
///
///
///
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/ColumnAccessor.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/ColumnAccessor.cs
new file mode 100644
index 0000000..dd49e4b
--- /dev/null
+++ b/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/ColumnAccessor.cs
@@ -0,0 +1,30 @@
+#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.Accessors
+{
+ internal class ColumnAccessor : MemberAccessor
+ where TEntity : class
+ {
+ private readonly MemberInfo _columnInfo;
+
+ public ColumnAccessor( MemberInfo columnInfo )
+ : base( columnInfo )
+ {
+ _columnInfo = columnInfo;
+ }
+ }
+}
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/EntityCollectionAccessor.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/EntityCollectionAccessor.cs
new file mode 100644
index 0000000..aca1db2
--- /dev/null
+++ b/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/EntityCollectionAccessor.cs
@@ -0,0 +1,28 @@
+#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
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace Achilles.Entities.Modelling.Mapping.Accessors
+{
+ internal class EntityCollectionAccessor : MemberAccessor
+ {
+ MemberInfo _entityCollectionInfo;
+
+ public EntityCollectionAccessor( MemberInfo entityReferenceInfo )
+ : base( entityReferenceInfo )
+ {
+ _entityCollectionInfo = entityReferenceInfo;
+ }
+ }
+}
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/EntityReferenceAccessor.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/EntityReferenceAccessor.cs
new file mode 100644
index 0000000..13e864e
--- /dev/null
+++ b/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/EntityReferenceAccessor.cs
@@ -0,0 +1,62 @@
+#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 Achilles.Entities.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+#endregion
+
+namespace Achilles.Entities.Modelling.Mapping.Accessors
+{
+ internal class EntityReferenceAccessor : MemberAccessor
+ where TEntity : class
+ {
+ MemberInfo _entityReferenceInfo;
+ EntityReference _entityReference;
+
+ public EntityReferenceAccessor( MemberInfo entityReferenceInfo )
+ : base( entityReferenceInfo )
+ {
+ _entityReferenceInfo = entityReferenceInfo;
+ }
+
+ public Type EntityType => typeof( TEntity );
+
+ public override object GetValue( TEntity entity )
+ {
+ return base.GetValue( entity );
+ }
+
+ public override void SetValue( TEntity entity, object value )
+ {
+ // The base.GetValue gets the entityReference<> class
+ var entityReference = base.GetValue( entity ) as IEntityReferenceSource;
+
+ //Type entityReferencePropertyType = entityReferenceProperty.GetType();
+
+ //// Get the EntitySet
+ //var entityReference = entityReferencePropertyType.GetGenericArguments().First();
+ //var entitySet = _context.EntitySets[ entityReference ];
+
+
+ if ( !entityReference.HasSource )
+ {
+ entityReference.SetSource( value as IEnumerable );
+ }
+
+ //base.SetValue( entity, value );
+ }
+ }
+}
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/ForeignKeyAccessor.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/ForeignKeyAccessor.cs
new file mode 100644
index 0000000..8c2225b
--- /dev/null
+++ b/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/ForeignKeyAccessor.cs
@@ -0,0 +1,30 @@
+#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.Accessors
+{
+ public class ForeignKeyAccessor : MemberAccessor
+ where TEntity : class
+ {
+ private readonly MemberInfo _foreignKeyInfo;
+
+ public ForeignKeyAccessor( MemberInfo foreignKeyInfo )
+ : base( foreignKeyInfo )
+ {
+ _foreignKeyInfo = foreignKeyInfo;
+ }
+ }
+}
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/ColumnAccessor.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/MemberAccessor.cs
similarity index 76%
rename from Achilles.Entities.Sqlite/Modelling/Mapping/ColumnAccessor.cs
rename to Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/MemberAccessor.cs
index 1a7738d..cc11807 100644
--- a/Achilles.Entities.Sqlite/Modelling/Mapping/ColumnAccessor.cs
+++ b/Achilles.Entities.Sqlite/Modelling/Mapping/Accessors/MemberAccessor.cs
@@ -11,38 +11,35 @@
#region Namespaces
using System;
-using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
#endregion
-namespace Achilles.Entities.Modelling.Mapping
+namespace Achilles.Entities.Modelling.Mapping.Accessors
{
- internal class ColumnAccessor : MemberAccessor
- where TEntity : class
+ public abstract class MemberAccessor
{
- private readonly MemberInfo _columnInfo;
+ protected Func _getter;
+ protected Action _setter;
- private Func _getter;
- private Action _setter;
-
- public ColumnAccessor( MemberInfo columnInfo )
- : base( columnInfo )
+ public MemberAccessor( MemberInfo memberInfo )
{
- _columnInfo = columnInfo;
+ MemberInfo = memberInfo ?? throw new System.ArgumentNullException( nameof( memberInfo ) );
CreateGetter();
CreateSetter();
}
- public override object GetValue( TMember entity ) => _getter( entity as TEntity );
+ protected MemberInfo MemberInfo { get; }
+
+ public virtual object GetValue( TEntity entity ) => _getter( entity );
- public override void SetValue( TMember entity, object value ) => _setter( entity as TEntity, value );
+ public virtual void SetValue( TEntity entity, object value ) => _setter( entity, value );
private void CreateGetter()
{
- if ( _columnInfo is PropertyInfo propertyInfo )
+ if ( MemberInfo is PropertyInfo propertyInfo )
{
ParameterExpression instance = Expression.Parameter( typeof( TEntity ), "instance" );
@@ -52,7 +49,7 @@ private void CreateGetter()
_getter = Expression.Lambda>( conversion, parameters ).Compile();
}
- else if ( _columnInfo is FieldInfo field )
+ else if ( MemberInfo is FieldInfo field )
{
ParameterExpression instance = Expression.Parameter( typeof( TEntity ), "instance" );
@@ -66,10 +63,10 @@ private void CreateGetter()
private void CreateSetter()
{
- if ( _columnInfo is PropertyInfo propertyInfo )
+ if ( MemberInfo is PropertyInfo propertyInfo )
{
var columnPropertySetMethod = propertyInfo.GetSetMethod();
- var setMethodParameterType = columnPropertySetMethod.GetParameters().First().ParameterType;
+ var setMethodParameterType = columnPropertySetMethod.GetParameters()[0].ParameterType;
var entityInstanceParameter = Expression.Parameter( typeof( TEntity ), "instance" );
var valueParameter = Expression.Parameter( typeof( object ), "value" );
@@ -81,7 +78,7 @@ private void CreateSetter()
_setter = Expression.Lambda>(
body, parameters ).Compile();
}
- else if ( _columnInfo is FieldInfo field )
+ else if ( MemberInfo is FieldInfo field )
{
var instanceParameter = Expression.Parameter( typeof( TEntity ), "instance" );
var valueParameter = Expression.Parameter( typeof( object ), "value" );
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/EntityMappingBuilder.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/EntityMappingBuilder.cs
index 08ad67a..6e1a378 100644
--- a/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/EntityMappingBuilder.cs
+++ b/Achilles.Entities.Sqlite/Modelling/Mapping/Builders/EntityMappingBuilder.cs
@@ -29,7 +29,7 @@ public class EntityMappingBuilder : IEntityMappingBuilder wher
{
#region Private Fields
- private EntityMappingCollection _entityMappings;
+ private EntityModel _model;
private readonly List _columnMappingBuilders = new List();
private readonly List _indexMappingBuilders = new List();
@@ -43,11 +43,11 @@ public class EntityMappingBuilder : IEntityMappingBuilder wher
///
/// Constructs a new EntityMappingBuilder instance.
///
- public EntityMappingBuilder( EntityMappingCollection entityMappings )
+ public EntityMappingBuilder( EntityModel model )
{
- _entityMappings = entityMappings;
+ _model = model;
- EntityMapping = entityMappings.GetOrAddEntityMapping( EntityType );
+ EntityMapping = model.GetOrAddEntityMapping( EntityType );
}
#endregion
@@ -168,7 +168,7 @@ public IEntityMapping Build()
if ( t != EntityType )
{
- var foreignKeyConstraintMapping = _entityMappings.GetOrAddEntityMapping( t );
+ var foreignKeyConstraintMapping = _model.GetOrAddEntityMapping( t );
foreignKeyConstraintMapping.ForeignKeyMappings.Add( hasManyMapping.ForeignKeyMapping );
}
else
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMapping.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMapping.cs
index 8e755bf..323f377 100644
--- a/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMapping.cs
+++ b/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMapping.cs
@@ -10,6 +10,7 @@
#region Namespaces
+using Achilles.Entities.Modelling.Mapping.Accessors;
using Achilles.Entities.Relational.Modelling.Mapping;
using System;
using System.Collections.Generic;
@@ -29,15 +30,24 @@ public class EntityMapping : IEntityMapping where TEntity : class
{
#region Fields
+ private EntityModel _model;
+
private Dictionary _columnProperties;
private Dictionary _foreignKeyProperties;
private Dictionary _relationshipProperties;
- //private Dictionary> ColumnGetters = new Dictionary>();
- //private Dictionary> ColumnSetters = new Dictionary>();
+ private Dictionary> ColumnAccessors
+ = new Dictionary>();
+
+ private Dictionary> ForeignKeyAccessors
+ = new Dictionary>();
- private Dictionary ColumnAccessors = new Dictionary();
+ private Dictionary>> EntityReferenceAccessors
+ = new Dictionary>>();
+ private Dictionary>> EntityCollectionAccessors
+ = new Dictionary>>();
+
#endregion
#region Constructor(s)
@@ -45,8 +55,10 @@ public class EntityMapping : IEntityMapping where TEntity : class
///
/// Constructs a new instance of .
///
- public EntityMapping()
+ public EntityMapping( EntityModel model )
{
+ _model = model;
+
InitializePropertyAndFieldMappings();
}
@@ -54,9 +66,14 @@ public EntityMapping()
#region Public Properties
- public object GetColumn( T entity, string propertyName ) where T : class => ColumnAccessors[ propertyName ].GetValue( entity as TEntity );
+ public object GetColumn( T entity, string propertyName ) where T : class
+ => ColumnAccessors[ propertyName ].GetValue( entity as TEntity );
- public void SetColumn( T entity, string propertyName, object value ) where T: class => ColumnAccessors[ propertyName ].SetValue( entity as TEntity, value );
+ public void SetColumn( T entity, string propertyName, object value ) where T: class
+ => ColumnAccessors[ propertyName ].SetValue( entity as TEntity, value );
+
+ public void SetEntityReference( T Entity, string propertyName, object source ) where T : class
+ => EntityReferenceAccessors[ propertyName ].SetValue( Entity as TEntity, source );
public List ColumnMappings { get; set; } = new List();
@@ -76,8 +93,14 @@ public EntityMapping()
#endregion
+ #region Internal Properties
+
+ internal EntitySet EntitySet => (EntitySet< TEntity>)_model.DataContext.EntitySets[ EntityType ];
+
+ #endregion
+
#region Public Methods
-
+
public void Compile()
{
_columnProperties = ColumnMappings.ToDictionary( m => m.ColumnName, m => m.ColumnInfo, IsCaseSensitive? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase );
@@ -87,6 +110,8 @@ public void Compile()
#endregion
+
+
#region Private Methods
private void CreateAccessors()
@@ -94,13 +119,32 @@ private void CreateAccessors()
// Columns...
foreach ( var columnMapping in ColumnMappings )
{
- ColumnAccessors.Add( columnMapping.PropertyName, new ColumnAccessor( columnMapping.ColumnInfo ) );
+ ColumnAccessors.Add( columnMapping.PropertyName, new ColumnAccessor( columnMapping.ColumnInfo ) );
}
- }
+ // Foreign Keys...
+ foreach ( var foreignKeyMapping in ForeignKeyMappings )
+ {
+ ForeignKeyAccessors.Add( foreignKeyMapping.PropertyName, new ForeignKeyAccessor( foreignKeyMapping.ForeignKeyProperty ) );
+ }
- private void CreateRelationshipSetters()
- {
+ // Relationship Mappings...
+ foreach ( var relationshipMapping in RelationshipMappings )
+ {
+ if ( relationshipMapping.IsMany )
+ {
+ EntityCollectionAccessors.Add(
+ relationshipMapping.RelationshipProperty.Name,
+ new EntityCollectionAccessor>( relationshipMapping.RelationshipProperty ) );
+ }
+ else
+ {
+ EntityReferenceAccessors.Add(
+ relationshipMapping.RelationshipProperty.Name,
+ new EntityReferenceAccessor>( relationshipMapping.RelationshipProperty ) );
+
+ }
+ }
}
///
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMappingCollection.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMappingCollection.cs
index 7c3ebfb..aa67b76 100644
--- a/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMappingCollection.cs
+++ b/Achilles.Entities.Sqlite/Modelling/Mapping/EntityMappingCollection.cs
@@ -22,16 +22,26 @@ namespace Achilles.Entities.Modelling.Mapping
///
/// Collection class for entity mappings.
///
- public class EntityMappingCollection //: IDictionary
+ internal class EntityMappingCollection
{
#region Fields
+ private EntityModel _model;
private ConcurrentDictionary _entityMappings = new ConcurrentDictionary();
#endregion
+ #region Constructor(s)
+
+ public EntityMappingCollection( EntityModel model )
+ {
+ _model = model;
+ }
+
+ #endregion
+
///
- /// TODO:
+ /// Gets an entity type if it is already in the collection or creates and adds the entity to the collection.
///
///
///
@@ -39,15 +49,12 @@ public IEntityMapping GetOrAddEntityMapping( Type entityType )
{
if ( !_entityMappings.TryGetValue( entityType, out IEntityMapping mapping ) )
{
- var EntityMappingType = typeof( EntityMapping<> );
- var mappingType = EntityMappingType.MakeGenericType( entityType );
+ var entityMappingType = typeof( EntityMapping<> );
+ var genericEntityMappingType = entityMappingType.MakeGenericType( entityType );
- mapping = Activator.CreateInstance( mappingType ) as IEntityMapping;
+ mapping = Activator.CreateInstance( genericEntityMappingType, _model ) as IEntityMapping;
_entityMappings[ entityType ] = mapping;
-
- // TJT: Review. Perhaps this is better done elsewhere
- mapping.Compile();
}
return mapping;
@@ -55,10 +62,12 @@ public IEntityMapping GetOrAddEntityMapping( Type entityType )
public void TryAddEntityMapping( Type entityType, IEntityMapping entityMapping )
{
+ // TJT: Review this method.
+
if ( _entityMappings.TryAdd( entityType, entityMapping ) )
{
// Compile the defined mapping into a column <-> member info lookup dictionary.
- entityMapping.Compile();
+ //entityMapping.Compile();
}
}
@@ -72,68 +81,9 @@ public IEntityMapping GetEntityMapping( Type entityType )
throw new ArgumentException( nameof( entityType ) );
}
- //#region IDictionary Implementation through _EntityMappingpings
-
- //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 bool IsReadOnly => ((IDictionary)_entityMappings).IsReadOnly;
-
- //public void Add( KeyValuePair item )
- //{
- // ((IDictionary)_entityMappings).Add( item );
- //}
-
- //public void Clear()
- //{
- // ((IDictionary)_entityMappings).Clear();
- //}
-
- //public bool Contains( KeyValuePair item )
- //{
- // return ((IDictionary)_entityMappings).Contains( item );
- //}
-
- //public bool ContainsKey( Type key )
- //{
- // return ((IDictionary)_entityMappings).ContainsKey( key );
- //}
-
- //public void CopyTo( KeyValuePair[] array, int arrayIndex )
- //{
- // ((IDictionary)_entityMappings).CopyTo( array, arrayIndex );
- //}
-
- //public IEnumerator> GetEnumerator()
- //{
- // return ((IDictionary)_entityMappings).GetEnumerator();
- //}
-
- //public bool Remove( Type key )
- //{
- // return ((IDictionary)_entityMappings).Remove( key );
- //}
-
- //public bool Remove( KeyValuePair item )
- //{
- // return ((IDictionary)_entityMappings).Remove( item );
- //}
-
- //public bool TryGetValue( Type key, out IEntityMapping value )
- //{
- // return ((IDictionary)_entityMappings).TryGetValue( key, out value );
- //}
-
- ////IEnumerator IEnumerable.GetEnumerator()
- ////{
- //// return ((IDictionary)_entityMappings).GetEnumerator();
- ////}
-
- //#endregion
}
}
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/IEntityMapping.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/IEntityMapping.cs
index ec474f6..3f49987 100644
--- a/Achilles.Entities.Sqlite/Modelling/Mapping/IEntityMapping.cs
+++ b/Achilles.Entities.Sqlite/Modelling/Mapping/IEntityMapping.cs
@@ -42,6 +42,8 @@ public interface IEntityMapping
void SetColumn( T entity, string propertyName, object value ) where T : class;
+ void SetEntityReference( T entity, string propertyName, object value ) where T : class;
+
void Compile();
}
}
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/IForeignKeyMapping.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/IForeignKeyMapping.cs
index 82976f7..92c3abe 100644
--- a/Achilles.Entities.Sqlite/Modelling/Mapping/IForeignKeyMapping.cs
+++ b/Achilles.Entities.Sqlite/Modelling/Mapping/IForeignKeyMapping.cs
@@ -30,7 +30,7 @@ public interface IForeignKeyMapping
string PropertyName { get; }
///
- /// Gets teh Reference key .
+ /// Gets the reference key property or field.
///
MemberInfo ReferenceKeyProperty { get; set; }
diff --git a/Achilles.Entities.Sqlite/Modelling/Mapping/MemberAccessor.cs b/Achilles.Entities.Sqlite/Modelling/Mapping/MemberAccessor.cs
deleted file mode 100644
index c2d71b0..0000000
--- a/Achilles.Entities.Sqlite/Modelling/Mapping/MemberAccessor.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-#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 33a8f49..2cdcfb3 100644
--- a/Achilles.Entities.Sqlite/Querying/EntityMaterializer.cs
+++ b/Achilles.Entities.Sqlite/Querying/EntityMaterializer.cs
@@ -141,6 +141,7 @@ internal object Materialize( IDictionary dictionary, object enti
if ( entity.GetType().IsPrimitive || entity is string )
{
object value;
+
if ( !dictionary.TryGetValue( "$", out value ) )
{
throw new InvalidCastException( "For lists of primitive types, include $ as the name of the property" );
@@ -151,11 +152,6 @@ internal object Materialize( IDictionary dictionary, object enti
return entity;
}
- // Once we have the instance we can attach an entity set source to the instance relationship properties
- var entityMapping = _model.GetEntityMapping( entity.GetType() );
-
- var relationshipMappings = entityMapping.RelationshipMappings;
-
var fieldsAndProperties = GetFieldsAndProperties( entity.GetType() );
foreach ( var fieldOrProperty in fieldsAndProperties )
@@ -163,49 +159,6 @@ internal object Materialize( IDictionary dictionary, object enti
var memberName = fieldOrProperty.Key.ToLower();
var memberInfo = fieldOrProperty.Value;
- var relationshipMapping = relationshipMappings.Where( r => r.RelationshipProperty == memberInfo ).FirstOrDefault();
-
- if ( relationshipMapping != null )
- {
- if ( relationshipMapping.IsMany )
- {
- //IEntityCollection entityCollection = memberInfo as IEntityCollection;
- }
- else
- {
- // First Get the type entity we are materializing
- Type entityType = entity.GetType();
-
- object entityReferenceProperty;
-
- if ( memberInfo.MemberType == MemberTypes.Property )
- {
- PropertyInfo propertyInfo = memberInfo as PropertyInfo;
-
- // Gets the property EntityReference class instance
- entityReferenceProperty = propertyInfo.GetValue( entity );
- }
- else
- {
- FieldInfo fieldInfo = memberInfo as FieldInfo;
-
- entityReferenceProperty = fieldInfo.GetValue( entity );
- }
-
- Type entityReferencePropertyType = entityReferenceProperty.GetType();
-
- MethodInfo attachSourceMethod = entityReferencePropertyType.GetMethod( "AttachSource" );
-
- // Get the EntitySet
- var entityReference = entityReferencePropertyType.GetGenericArguments().First();
- var entitySet = _context.EntitySets[ entityReference ];
-
- attachSourceMethod.Invoke( entityReferenceProperty, new object[] { entitySet } );
- }
-
- continue;
- }
-
object value;
// Handle populating simple members on the current type
@@ -288,9 +241,42 @@ internal object Materialize( IDictionary dictionary, object enti
}
}
+ SetDeferredLoading( entity );
+
return entity;
}
+ private void SetDeferredLoading ( object entity )
+ {
+ // Once we have the entity instance we can attach an entity set source to the instance relationship properties
+ var entityMapping = _model.GetEntityMapping( entity.GetType() );
+
+ var relationshipMappings = entityMapping.RelationshipMappings;
+
+ foreach ( var relationshipMapping in relationshipMappings )
+ {
+ var foreignKey = relationshipMapping.ForeignKeyMapping;
+
+ if ( relationshipMapping.IsMany )
+ {
+ //entityMapping.SetEntityCollection(
+ // entity,
+ // relationshipMapping.RelationshipProperty.Name,
+ // relationshipMapping.ForeignKeyMapping );
+ }
+ else
+ {
+ entityMapping.SetEntityReference(
+ entity,
+ relationshipMapping.RelationshipProperty.Name,
+ relationshipMapping.ForeignKeyMapping );
+ }
+
+ continue;
+ }
+
+ }
+
///
/// Populates the given instance's properties where the IDictionary key property names
/// match the type's property names case insensitively.