Динамическое беглое картографирование с помощью EF4.1

Я хочу динамически создать свою модель данных для работы с некоторыми существующими классами и настраиваемым файлом сопоставления XML, потому что у меня много существующих таблиц и много существующих бизнес-классов (может быть, безумие, я не знаю).

Для свойств, которые используют другие имена столбцов или не соответствуют существующим столбцам, я хочу вызвать .Ignore() и .HasColumnName(), но я хочу сделать это динамически.

Итак, я хочу иметь возможность делать такие вызовы, но я хочу делать их динамически на основе отражения и файла конфигурации XML с использованием Linq.Expressions (который мне никогда не приходилось использовать):

modelBuilder.Entity<Product>().Property(p => p.QuantityInStock).HasColumnName("UnitsInStock");

or

modelBuilder.Entity<Product>().Ignore(p => p.QuantityInStock);

Это то, что я пытаюсь (в конечном итоге я буду ссылаться на свою карту XML, чтобы определить, какие свойства отображать, а какие игнорировать):

Type entityType = typeof(Product);

var config = modelBuilder.GetType().GetMethod("Entity")
    .MakeGenericMethod(entityType)
    .Invoke(modelBuilder, null);

var ignore = config.GetType().GetMethod("Ignore").MakeGenericMethod(entityType);

var paramEx = Expression.Parameter(entityType);
var lambdaEx = Expression.Lambda(Expression.Property(paramEx, "QuantityInStock"), paramEx);

ignore.Invoke(config, new[] { lambdaEx });

Но мое лямбда-выражение неверно:

Object of type 'System.Linq.Expressions.Expression`1[System.Func`2[ConsoleApplication2.Product,System.Int16]]' 
cannot be converted to type 
'System.Linq.Expressions.Expression`1[System.Func`2[ConsoleApplication2.Product,ConsoleApplication2.Product]]'.

person powlette    schedule 19.03.2012    source источник


Ответы (2)


Аргумент универсального типа неверен для метода Ignore. Измените свой код на это:

var paramEx = Expression.Parameter(entityType);
var prop = Expression.Property(paramEx, "QuantityInStock");
var lambdaEx = Expression.Lambda(prop, paramEx);
var ignore = config.GetType().GetMethod("Ignore").MakeGenericMethod(prop.Type);

РЕДАКТИРОВАТЬ: вызов HasColumnName:

var property = config.GetType().GetMethod("Property", new Type[] { lambdaEx.GetType() });
var hasColumnName = property.ReturnType.GetMethod("HasColumnName");

hasColumnName.Invoke(
    property.Invoke(config, new[] { lambdaEx }),
    new[] { "UnitsInStock" });

Однако это не работает для структур, исключенных из списка перегрузок, таких как long или подобных, в этих случаях значение property будет null. Следовательно, вам придется искать общий метод Property с GetMethods и выбирать подходящий (с типом Nullable<T> или без него в параметре Expression).

person Balazs Tihanyi    schedule 19.03.2012
comment
Спасибо, это было. Можете ли вы помочь мне вызвать .HasColumnName()? Это сложнее, потому что .Property имеет много переопределений, и я не уверен, как получить правильный вызов. - person powlette; 19.03.2012

ИМО, это не предназначено для Fluent API. Вся цель Fluent API состоит в том, чтобы предоставить более читаемый и простой способ настройки, обеспечивая при этом безопасность во время компиляции. Я не вижу ничего подобного при таком подходе.

Лучший способ внедрить конфигурацию — использовать класс EntityTypeConfiguration и добавить его в класс ModelBuilder.

person Eranga    schedule 19.03.2012
comment
Ну, у меня есть классы с сотней свойств, ни одно из которых не соответствует столбцам в таблице, и я не хочу явно игнорировать их все. Лучше было бы самому изучить конфигурацию table/model/xml и динамически вызывать .Ignore. - person powlette; 19.03.2012
comment
Попытка установить что-то, что не предназначено для этой цели, только усугубит ситуацию. Лучше иметь набор сущностей EF, которые будут сопоставлены с вашими бизнес-классами. - person Eranga; 19.03.2012