1

I want to persist some data on a database using Entity Framework.
I have some bigger POCOs but I want to store some of the properties only.

I know that I can achieve this with the Fluent API by using the Ignore() method. But is there also the possibility of not only ignoring a defined property but all properties but the defined?
So if you have a POCO like this:

public class MyPoco
{
    public int Id { get; set; }
    public string Name { get; set; }
    .
    .
    .
    public int SomeSpecialId { get; set; }
}

And you only want to store the Id and the SomeSpecialId, you would do:

protected override void OnModelCreating(DbModelBuilder builder)
{
    builder.Entity<MyPoco>().Ignore(x => x.Name);
    builder.Entity<MyPoco>().Ignore(x => x.WhatEver);
    .
    .
    .
    // ignore everything but Id and SomeSpecialId
    base.OnModelCreating(builder);
}

Problem now is that if you have to extend the POCO but don't want to persist those extended properties you also have to change the OnModelCreating() method. So is there a way of doing something like:

public override void OnModelCreating(DbModelBuilder builder)
{
    builder.Entity<MyPoco>().IgnoreAllBut(x => x.Id, x.SomeSpecialId);
    base.OnModelCreating(builder);
}
Simon Linder
  • 3,378
  • 4
  • 32
  • 49

2 Answers2

3

You can write an extension method that will do that. The code is not simple because you need to work with expression trees.

Here is your IgnoreAllBut method:

public static EntityTypeConfiguration<T> IgnoreAllBut<T>(this EntityTypeConfiguration<T> entityTypeConfiguration,
        params Expression<Func<T, object>>[] properties) where T : class
{
    // Extract the names from the expressions
    var namesToKeep = properties.Select(a =>
    {
        var member = a.Body as MemberExpression;
        // If the property is a value type, there will be an extra "Convert()"
        // This will get rid of it.
        if (member == null)
        {
            var convert = a.Body as UnaryExpression;
            if (convert == null) throw new ArgumentException("Invalid expression");
            member = convert.Operand as MemberExpression;
        }
        if (member == null) throw new ArgumentException("Invalid expression");
        return (member.Member as PropertyInfo).Name;
    });
    // Now we loop over all properties, excluding the ones we want to keep
    foreach (var property in typeof(T).GetProperties().Where(p => !namesToKeep.Contains(p.Name)))
    {
        // Here is the tricky part: we need to build an expression tree
        // to pass to Ignore()
        // first, the parameter
        var param = Expression.Parameter(typeof (T), "e");
        // then the property access
        Expression expression = Expression.Property(param, property);
        // If the property is a value type, we need an explicit Convert() operation
        if (property.PropertyType.IsValueType)
        {
            expression = Expression.Convert(expression, typeof (object));
        }
        // last step, assembling everything inside a lambda that
        // can be passed to Ignore()
        var result = Expression.Lambda<Func<T, object>>(expression, param);
        entityTypeConfiguration.Ignore(result);
    }
    return entityTypeConfiguration;
}
Najkin
  • 932
  • 1
  • 7
  • 16
  • Thanks ! But how can I make a property expression to function Property() ? I used the same but it says "The type 'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic method 'StructuralTypeConfiguration.Property(Expression>) – Alexandre TRINDADE Mar 19 '18 at 07:32
1

You can mark individual properties as NotMapped within the class itself.

public class MyPoco
{
    public int Id { get; set; }

    [NotMapped]
    public string Name { get; set; }

    public int SomeSpecialId { get; set; }
}

Doesn't solve your issue of 'ignore everything but this' but might make it obvious what is and isn't included.

Jamie Burns
  • 1,258
  • 9
  • 21
  • Well this is not easy to explain. I cannot do this because this would set the property to be ignored globally. The POCO is within another project (DLL) than the EF persistance. So it might be that the POCO is to be stored with 2 properties in on project but with different properties in another project. – Simon Linder Jun 26 '15 at 07:49