Есть ли способ вызвать универсальные методы репозитория для объекта, созданного во время выполнения с помощью codeDOM?

Я использую codeDOM для создания классов сущностей во время выполнения. У меня также есть общий репозиторий для работы с различными функциями БД. Вот метод Insert в качестве примера метода в моем универсальном репозитории:

public void Insert<TEntity>(TEntity entity) where TEntity : class, IBusinessEntity
{
    if (entity == null)
    {
        throw new ArgumentNullException("entity");
    }

    TEntity existing = Existing(entity);
    if (existing == null)
    {
        _context.Set<TEntity>().Add(entity);
        this._context.SaveChanges();
    }
}

Вот пример кода того, как я генерирую класс сущности и как создать сущность на основе этого класса сущности с помощью codeDOM:

//Generate the fields of the new entity class
EntityGenerator.EntityFieldInfo entityField1 = new EntityGenerator.EntityFieldInfo("Name", typeof(string), RelationshipType.NoRelation);
EntityGenerator.EntityFieldInfo entityField2 = new EntityGenerator.EntityFieldInfo("Shape", typeof(string), RelationshipType.NoRelation);
ICollection<EntityGenerator.EntityFieldInfo> entityFieldList = new List<EntityGenerator.EntityFieldInfo> { entityField1, entityField2 };

// Create the new entity class using the fields established above 
// as well as the name of the entity (typeName = "Thing")
string typeName = "Thing";
EntityGenerator.CreateEntityClass(entityFieldList, typeName);
CompilerResults results = EntityGenerator.GetCompiledEntity(typeName);

// Create an entity instance based on the new entity class that was just created
Object newThing = EntityGenerator.CreateInstanceOfEntity(results, typeName);
SetObjectField(newEntity, "Name", "Box");
SetObjectField(newEntity, "Shape", "Cuboid");

Как видите, newThing (экземпляр новой сущности) является типом Object. Если бы это был жестко закодированный класс сущностей, я мог бы просто сказать

Thing newThing;

Но объект Thing, созданный CodeDOM, не является жестко запрограммированным классом, поэтому мне приходится использовать тип Object вместо типа Thing. Это проблема, потому что я использую общий репозиторий. Допустим, я хочу вставить этот объект в базу данных. Я хотел бы позвонить:

myRepository.Insert<Thing>(newThing);

Однако Thing только что был создан CodeDOM во время выполнения, поэтому он не является классом, что означает, что он не может находиться внутри ‹>. Возможно, вы заметили выше в моем методе Insert, что TEntity также является IBusinessEntity. Если я попытаюсь

myRepository.Insert<IBusinessEntity>(newThing);

Я получаю сообщение об ошибке:

Тип аргумента «объект» не может быть назначен типу параметра «Models.IBusinessEntity».

Если я попробую без чего-либо внутри ‹>, вот так:

мойРепозиторий.Вставить(новаяВещь);

Я получаю сообщение об ошибке:

Тип «объект» должен быть преобразован в «Models.IBusinessEntity», чтобы использовать его в качестве параметра «TEntity» в универсальном методе «void Insert (TEntity)».

Кто-нибудь знает, как я могу согласовать этот объект, созданный codeDOM, с общим репозиторием? Поможет ли рефлексия? Было бы неплохо, если бы рефлексия каким-то образом могла дать мне класс Thing, который можно было бы передать в ‹>. Также я должен отметить, что все объекты, которые я создаю с помощью CodeDOM, расширяют IBusinessEntity.


person Drew    schedule 18.06.2015    source источник
comment
Ваш сгенерированный тип реализует интерфейс? Даже если бы это было так, я не думаю, что у вас может быть «интерфейс DbSet‹», потому что EF не будет знать, какой объект создавать при материализации сущностей. Мне также непонятно, почему вы генерируете типы на лету, если модель должна соответствовать базе данных...   -  person Pawel    schedule 19.06.2015
comment
Мне приходится генерировать типы на лету, потому что мы позволяем пользователям создавать свои собственные объекты. Итак, мы извлекаем данные из таблиц sql о том, как пользователь хочет, чтобы его объект выглядел, а затем мы создаем его с помощью codeDOM. И я не знаю, как сохранить этот объект в базе данных.   -  person Drew    schedule 19.06.2015


Ответы (1)


Я думаю, что это будет сложно заставить работать, потому что DbSet, содержащиеся в DbContext, используются EF для создания сопоставлений. Как вы думаете, как их создать?

В любом случае, вам не нужен тип для работы с EF, вы можете часто использовать GetType. В ваших методах (Existing(.) отсутствует, но я думаю, что он похож) вы можете использовать

public void Insert(object entity)
{
    if (entity == null)
        throw new ArgumentNullException("entity");

    if (!(entity is IBusinessEntity))
        throw new ArgumentInvalidException("entity is not an IBusinessEntity");

    object existing = Existing(entity);
    if (existing == null)
    {
        _context.Set(entity.GetType()).Add(entity);
        this._context.SaveChanges();
    }

}

Используя Set‹> или Set(.), я совершенно уверен, что EF будет выполнять поиск в сопоставлениях, созданных на основе DbSet, содержащихся в DbContext. Я не могу вспомнить точное исключение, но я сею его в разное время (когда я использовал DbContext.Set(myEntityType)).

person bubi    schedule 19.06.2015
comment
Да, я думаю, ты прав. Я полагаю, что не могу использовать универсальный репозиторий, поэтому мне приходится жестко кодировать все DbSet в моем классе контекста. И тогда в моих методах я могу просто проверить тип объекта. Спасибо! - person Drew; 19.06.2015