Question

I'm dynamically creating my DbContext by iterating over any entities that inherit from EntityBase and adding them to my Context:

    private void AddEntities(DbModelBuilder modelBuilder)
    {
        var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            var entityTypes = assembly.GetTypes()
                .Where(x => x.IsSubclassOf(typeof(EntityBase)) && !x.IsAbstract);
            foreach (var type in entityTypes)
            {
                dynamic entityConfiguration = entityMethod.MakeGenericMethod(type).Invoke(modelBuilder, new object[] { });
                EntityBase entity = (EntityBase)Activator.CreateInstance(type);

                //Add any specific mappings that this class has defined
                entity.OnModelCreating(entityConfiguration);
            }
        }
    }

That way, I can have many namespaces but just one generic repository in my base namespace that's used everywhere. Also, in apps that make use of multiple namespaces, the base repository will already be setup to use all the entities in all the loaded namespaces. My problem is, I don't want to make EntityFramework.dll a dependency of every namespace in the company. So I'm calling OnModelCreating and passing the EntityTypeConfiguration to the class so it can add any mappings. This works fine and here's how I can add a mapping to tell the model that my "Description" property comes from a column called "Descriptor":

class Widget... {
    public override void OnModelCreating(dynamic entity)
    {
        System.Linq.Expressions.Expression<Func<Widget, string>> tmp = 
             x => x.Description;
        entity.Property(tmp).HasColumnName("Descriptor");
    }

The good thing is, my entity class has no reference to EF, this method is only called once, when the context is created and if we scrap EF and go to something else in the future, my classes won't have all sorts of attributes specific to EF in them.

The problem is, it's super ugly. How can I let the model know about column mappings and keys in a simpler way than creating these Expressions to get properties to map without hard coding references to EF all over my poco classes?

Was it helpful?

Solution

You could define your own Attributes and use these to control the configuration within OnModelCreating(). You should be able to gain (using reflection) all the details you need for column mapping in one linq query a second query for the creation of the key.

public class DatabaseNameAttribute : Attribute
{
    private readonly string _name;
    public DatabaseNameAttribute(string name)
    {
        _name = name;
    }
    public string Name
    {
        get
        {
            return _name;
        }
    }
}

public class KeySequenceAttribute : Attribute
{
    private readonly int _sequence;
    public KeySequenceAttribute(int sequence)
    {
        _sequence = sequence;
    }
    public int Sequence
    {
        get
        {
            return _sequence;
        }
    }
}

[DatabaseName("BlogEntry")]
public class Post
{
    [DatabaseName("BlogId")]
    [KeySequence(1)]
    public int id { get; set; }
    [DatabaseName("Description")]
    public string text { get; set; }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top