Динамический запрос сущностей из Entity Framework для связи с первичным Entity
Я знаю, что название не было лучшим, но вот что я действительно хочу достичь.
У меня есть подробное представление, которое представляет Entity1 и его ассоциации. Я фиксирую имена и значения свойств в паре ключ / значение. В настоящее время я использую отражение, чтобы установить свойства сущности на соответствующие значения для не ассоциаций. Я сомневаюсь, что это самый эффективный способ, но я не смог найти лучший способ, используя деревья выражений. Поэтому теперь мне нужно установить ассоциации Entity1 для их соответствующих объектов на основе первичного ключа этих ассоциаций объектов, назовите их Entity2-4.
Итерируя Свойства Entity1, я не знаю, как построить динамический запрос к Entity2-4 и установить Entity1.association для соответствующего объекта. Вот код, который у меня есть:
foreach (string k in e.Values.Keys)
{
if (e.Values[k] != null && !String.IsNullOrEmpty(e.Values[k].ToString()))
{
System.Type objectType = Entity1.GetType();
PropertyInfo[] p = objectType.GetProperties();
foreach (PropertyInfo pi in p)
{
// set Entity1.Property for non associations (works just fine)
if (pi.Name == k)
{
System.Type t = pi.PropertyType;
pi.SetProperty(e.Values[k].ToString(), Entity1);
break;
}
// when i see pi.Name contain Reference, I know I'm working on an association
else if (pi.Name.Contains("Reference"))
{
// k is in the form of Entity.Property
var name = pi.Name.Left("Reference");
var keys = k.Split('.');
var ent = keys[0];
var prop = keys[1];
if (name == ent)
{
// here I need to obtain an instance from the db
// ie generate my dynamic query to the Entity with the name
// contained within the var "ent"
// I tried using reflection and could instantiate the entity
// but it did me no good as I needed the entity from the db
var entityInstance = some dynamic query;
// here I need to set the association of Entity1 to entityInstance from above
// normally I would use reflection, but I'm not sure that would work
// since EntityReference is the actual property returned by reflection
Entity1.SetAssocation(prop, Entity2);
break;
}
}
}
}
}
РЕДАКТИРОВАТЬ
Мне в основном нужно создать сущность и ее сущности ассоциации, чтобы я мог представить их в контекст данных. Объекты 2-4 существуют в БД, мне нужно запросить у БД экземпляры, с которыми я могу связать их с новым объектом 1, который я создаю и собираюсь отправить.
Моя базовая модель:
entity1
Entity1.ID
Entity1.Prop1
Entity1.Prop2
Entity1.Prop3
Entity1.Entity2
Entity1.Entity3
Entity1.Entity4
entity2
Entity2.ID
Entity2.Name
Entity3
Entity3.ID
Entity3.Name
Entity4
Entity4.ID
Entity4.Name
2 ответа
У нас было углубленное обсуждение о том, как получить metadata
вне DbContext
, Вот несколько ссылок для начала. И я добавлю некоторые конкретные комментарии.
Как программно читать метаданные EF DbContext?
Краткое резюме (но вы должны проверить там больше):
using (var db = new MyDbContext())
{
var objectContext = ((IObjectContextAdapter)db).ObjectContext;
var container = objectContext.MetadataWorkspace.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace);
var dependents = ((EntitySet)(set)).ForeignKeyDependents;
var principals = ((EntitySet)(set)).ForeignKeyPrincipals;
var navigationProperties = ((EntityType)(set.ElementType)).NavigationProperties;
// and e.g. for many-to-many (there is more for other types)
ManyToManyReferences = navigationProperties.Where(np =>
np.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many &&
np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
.Select(np => Extensions.CreateLambdaExpression<TEntity>(np.Name))
.ToList();
}
@Goran Obradovic проделал большую работу, чтобы обернуть то, что я начал, в набор повторно используемых запросов (мои заслуги перед ним:)).
Я разработал всю другую информацию, которая там есть. Это только для DataSpace.CSpace
(что наиболее полезно для вас), но есть и DataSpace.SSpace
и т. д. - это больше для создания SQL-запросов и т. д. Я поставлю большинство ссылок внизу.
Особенности:
В вашем случае может быть полезно следующее:
(примечание: я не совсем уверен, что вы ищете, но я пытаюсь
guess
вот в каком направлении вы движетесь)db.Set<Worker>().Find(1);
Является ли общий метод для доступа DbSet
для конкретной сущности.
Вы также можете построить его из Type
если вам нужно, чтобы он был полностью динамичным, например...
(Я всегда хотел сделать это:)
MethodInfo setMethod = typeof(DbContext).GetMethod("Set", new Type[]{});
MethodInfo genericSetMethod = setMethod.MakeGenericMethod(new Type[] { typeof(YourEntity) });
var set = genericSetMethod.Invoke(db, new object[] {});
Поместите свое лицо - или ваше Type
вместо typeof(YourEntity)
,
Затем вы можете продолжить и запросить, например, для Find(id)
- для этого лица - для получения конкретных ценностей и т. д.
Это настолько динамично, насколько это возможно - я не уверен, что это то, чего вы хотите, - но я просто выкидываю вещи здесь, на случай, если вам это нужно.
Это должно помочь вам начать, по крайней мере, я надеюсь.
ссылки по теме :
(все мои посты - некоторые могут быть более или менее актуальными, но могут помочь)
Как программно читать метаданные EF DbContext?
Как проверить модульным тестом, что свойства помечены как вычисленные в модели ORM?
Схема Get Model для программного создания базы данных с использованием поставщика, который не поддерживает CreateDatabase
Программное преобразование данных в EF5 Code Первая миграция
Так что я не смог выполнить это динамически. Но вот мое рабочее решение. Кто-нибудь может посоветовать, как выполнить это динамически?
foreach (string k in e.Values.Keys)
{
if (e.Values[k] != null && !String.IsNullOrEmpty(e.Values[k].ToString()))
{
System.Type objectType = roster.GetType();
PropertyInfo[] p = objectType.GetProperties();
foreach (PropertyInfo pi in p)
{
if (pi.Name == k)
{
System.Type t = pi.PropertyType;
pi.SetProperty(e.Values[k].ToString(), roster);
break;
}
else if (pi.Name.Contains("Reference"))
{
var name = pi.Name.Left("Reference");
var keys = k.Split('.');
var entityName = keys[0];
var prop = keys[1];
if (name == entityName )
{
var val = e.Values[k].ToString();
switch (pi.Name)
{
case "Entity2Reference":
Entity1.Entity2Reference.EntityKey = new EntityKey("MyEntities." + entityName + "s", prop, val);
break;
case "Entity3Reference":
Entity1.Entity3Reference.EntityKey = new EntityKey("MyEntities." + entityName + "s", prop, val);
break;
case "Entity4Reference":
Entity1.Entity4Reference.EntityKey = new EntityKey("MyEntities." + entityName + "s", prop, Int64.Parse(val));
break;
}
}
}
}
}
}