Created
March 7, 2017 08:57
-
-
Save hidegh/36d92380c720804dee043fde8a863ecb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Data.Entity; | |
using System.Data.Entity.ModelConfiguration; | |
using System.Linq; | |
using System.Reflection; | |
namespace EF6x_code_first_persistence.Mappings.Core | |
{ | |
/// <summary> | |
/// Allows us to register conventions with a single call and also to pass in custom NamespaceToDbSchemaConvertor in ctor if given custom IConvention supports it. | |
/// </summary> | |
public static class MappingExtensions | |
{ | |
public delegate bool MappingFilterDelegate(Type mappingClass, Type entity); | |
public static void RegisterMappingsFrom<TAssembly>(this DbModelBuilder modelBuilder, MappingFilterDelegate filter = null) | |
{ | |
var mappingsAssembly = typeof(TAssembly); | |
var entityTypeConfigurationTypesToRegister = mappingsAssembly.Assembly | |
.GetTypes() | |
.Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)) | |
.Where(type => | |
{ | |
var entity = type.BaseType.GetGenericArguments()[0]; | |
var mappingClass = type; | |
if (filter == null) | |
return true; | |
return filter(mappingClass, entity); | |
}) | |
.ToList(); | |
foreach (var entityTypeconfigurationType in entityTypeConfigurationTypesToRegister) | |
{ | |
dynamic configurationInstance = Activator.CreateInstance(entityTypeconfigurationType); | |
modelBuilder.Configurations.Add(configurationInstance); | |
} | |
} | |
public static void RegisterMappingsFromInsideAssemblyAndNamespaceOf<TMapMarker>(this DbModelBuilder modelBuilder, MappingFilterDelegate filter = null) | |
{ | |
var mappingMarker = typeof(TMapMarker); | |
var mappingMarkerNS = mappingMarker.Namespace; | |
RegisterMappingsFrom<TMapMarker>(modelBuilder, (mappingClass, entity) => | |
{ | |
// make sure we're inside the desired namespace | |
if (!mappingClass.FullName.StartsWith(mappingMarkerNS + ".")) | |
return false; | |
// do additional custom filter logic | |
if (filter == null) | |
return true; | |
return filter(mappingClass, entity); | |
}); | |
} | |
public static void IgnoreNonMappedProperties<T>(this EntityTypeConfiguration<T> mapper) where T : class | |
{ | |
var entityType = typeof(T); | |
var entityProperties = entityType | |
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) | |
.Where(c => c.GetMethod != null && c.GetMethod.IsPrivate == false) | |
.ToArray(); | |
var mapperType = mapper.GetType(); | |
var configuration = mapperType | |
.GetProperty("Configuration", BindingFlags.Instance | BindingFlags.NonPublic) | |
.GetValue(mapper); | |
var configurationType = configuration.GetType(); | |
var configuredProperties = ((IEnumerable<PropertyInfo>) | |
configurationType | |
.GetProperty("ConfiguredProperties", BindingFlags.Instance | BindingFlags.NonPublic) | |
.GetValue(configuration) | |
) | |
.ToArray(); | |
var configurationIgnoreMethod = configurationType.GetMethod("Ignore"); | |
foreach (var p in entityProperties) | |
{ | |
// skip if property is mapped... | |
if (configuredProperties.FirstOrDefault(c => c.Name == p.Name) != null) | |
continue; | |
// ignore properties that aren't mapped manually... | |
configurationIgnoreMethod.Invoke(configuration, new object[] { p }); | |
} | |
} | |
} | |
} | |
/* | |
* https://github.com/aspnet/EntityFramework/issues/2805 | |
* | |
* https://daveaglick.com/posts/custom-entity-type-configurations-in-entity-framework-code-first-part-1 | |
* https://daveaglick.com/posts/custom-entity-type-configurations-in-entity-framework-code-first-part-2 | |
*/ |
FAIL:
This seems to work fine, but messes up bidirectional 1:N relations, where parent does it's configuration for both of the side, so configuring (N:1) from the child side won't be possible (EF won't allow it) and thus the back-ref. property will be ignored, even in case where we wan't to use it...
As a desperate measure to avoid un-mapping of custom properties on my entities I decided to use get/set functions...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's a code snippet, to make sure EF6 will use only properties you map manually. Usage is simple, inside mapping class call the IgnoreNonMappedProperties extension method after configuring your properties.