public class Profile : EntityBase
{
[PrimaryKey]
public int ProfileID { get; set; }
public string NickName { get; set; }
[Association(ThisKey = "Parent", OtherKey = "CategoryID", CanBeNull = true)]
public Category ParentCategory { get; set; }
}
public class Category : EntityBase
{
[PrimaryKey, Identity]
public int CategoryID { get; set; }
public string Name { get; set; }
}
Вот вопрос, как бы так сделать, чтобы при получении Profile, он автоматически грузил его Category. Этож не lazy-loading это наоборот. В настоящий момент для загрузки приходиться писать нечто вроде:
Здравствуйте, Игорь Евгеньевич, Вы писали:
ИЕ>Вот вопрос, как бы так сделать, чтобы при получении Profile, он автоматически грузил его Category. Этож не lazy-loading это наоборот. В настоящий момент для загрузки приходиться писать нечто вроде:
ИЕ>Select(p => new { Prof = p, Cat = p.ParentCategory });
ИЕ>Но это как то не круто.
Это как раз таки круто. Сама суть LINQ в том, что код отображения БД на классы находится в коде и контроллируется компилятором. Если тебе это не нужно, то зачем вообще тебе LINQ?
... << RSDN@Home 1.2.0 alpha 4 rev. 1476 on Windows 7 6.1.7600.0>>
Здравствуйте, AndrewVK, Вы писали:
ИЕ>>Но это как то не круто.
AVK>Это как раз таки круто. Сама суть LINQ в том, что код отображения БД на классы находится в коде и контроллируется компилятором. Если тебе это не нужно, то зачем вообще тебе LINQ?
Я просто хочу получить список Профайлов и использовать информацию из связанных таблиц. Тоесть написать: question.ParentCategory.Name. А так мне прийдёться все форен кеи, которых бывает по 10 штук сливать отдельно в класс (не всегда аноним подойдёт), который ещё и писать надо.
Здравствуйте, Игорь Евгеньевич, Вы писали:
ИЕ>Я просто хочу получить список Профайлов и использовать информацию из связанных таблиц. Тоесть написать: question.ParentCategory.Name.
А что, всякие DBManager.ExecuteList не подходят?
... << RSDN@Home 1.2.0 alpha 4 rev. 1476 on Windows 7 6.1.7600.0>>
Здравствуйте, Игорь Евгеньевич, Вы писали:
ИЕ> public class Profile : EntityBase ИЕ> { ИЕ> [PrimaryKey] ИЕ> public int ProfileID { get; set; } ИЕ> public string NickName { get; set; }
ИЕ> [Association(ThisKey = "Parent", OtherKey = "CategoryID", CanBeNull = true)] ИЕ> public Category ParentCategory { get; set; } ИЕ> }
ИЕ> public class Category : EntityBase ИЕ> { ИЕ> [PrimaryKey, Identity] ИЕ> public int CategoryID { get; set; } ИЕ> public string Name { get; set; } ИЕ> }
ИЕ>Вот вопрос, как бы так сделать, чтобы при получении Profile, он автоматически грузил его Category. Этож не lazy-loading это наоборот. В настоящий момент для загрузки приходиться писать нечто вроде:
ИЕ>Select(p => new { Prof = p, Cat = p.ParentCategory });
ИЕ>Но это как то не круто.
а что не нравиться, в L2S надо выписывать это через LoadWith, а здесь удобнее.
Здравствуйте, cadet354, Вы писали:
C>Здравствуйте, Игорь Евгеньевич, Вы писали:
ИЕ>>Select(p => new { Prof = p, Cat = p.ParentCategory });
ИЕ>>Но это как то не круто. C>а что не нравиться, в L2S надо выписывать это через LoadWith, а здесь удобнее.
Не знаю как автора, а меня напрягает анонимный тип. Его ж потом никуда не передашь, ни в какой метод.
Можно как то так писать:
var q = db.GetTable<Profile>().Select(p => new { Profile = p, ParentCategory = p.ParentCategory}).ToArray();
foreach (var r in q)
{
r.Profile.ParentCategory = r.ParentCategory;
}
return q.Select(r => r.Profile);
Здравствуйте, Jack128, Вы писали:
J>Здравствуйте, cadet354, Вы писали:
C>>Здравствуйте, Игорь Евгеньевич, Вы писали:
ИЕ>>>Select(p => new { Prof = p, Cat = p.ParentCategory });
ИЕ>>>Но это как то не круто. C>>а что не нравиться, в L2S надо выписывать это через LoadWith, а здесь удобнее.
J>Не знаю как автора, а меня напрягает анонимный тип. Его ж потом никуда не передашь, ни в какой метод.
а причем тут анонимный тип к вопросу топикстартеру, простой запрос
from p in db.Profile
select new Profile {
ProfileID = p.ProfileID
ParentCategory = p.ParentCategory
};
не работает?
к сожалению сейчас сам проверить не могу, но в документации описана сходная задача между заказами и заказчиками.
Здравствуйте, cadet354, Вы писали:
C>Здравствуйте, Jack128, Вы писали:
J>>Здравствуйте, cadet354, Вы писали:
C>>>Здравствуйте, Игорь Евгеньевич, Вы писали:
ИЕ>>>>Select(p => new { Prof = p, Cat = p.ParentCategory });
ИЕ>>>>Но это как то не круто. C>>>а что не нравиться, в L2S надо выписывать это через LoadWith, а здесь удобнее.
J>>Не знаю как автора, а меня напрягает анонимный тип. Его ж потом никуда не передашь, ни в какой метод. C>а причем тут анонимный тип к вопросу топикстартеру, простой запрос C>
C>from p in db.Profile
C>select new Profile {
C> ProfileID = p.ProfileID
C> ParentCategory = p.ParentCategory
C>};
C>
C>не работает? C>к сожалению сейчас сам проверить не могу, но в документации описана сходная задача между заказами и заказчиками.
В результате 2х дней размышлений, родилось общее простое решение заменитель Select, которое позволяет загружать вместе с обычными полями, также первый уровень ассоциаций. Работает он также как показано в примере, просто переприсваивая все свойства. Не проверено скорость работы, вероятно эффективней было бы кешировать эти лямбды при загрузке, для каждого класса.
public static class Extensions
{
public static IQueryable<TSource> SelectAssoc<TSource>(this IQueryable<TSource> source)
{
ParameterExpression ps = Expression.Parameter(typeof(TSource), "p");
List<MemberBinding> binding = new List<MemberBinding>();
var props = typeof(TSource).GetProperties();
foreach (var prop in props)
{
if (prop.GetSetMethod() == null) continue;
binding.Add(
Expression.Bind(
prop.GetSetMethod(),
Expression.Property(ps, prop.GetGetMethod())
)
);
}
var lambda = Expression.Lambda<Func<TSource, TSource>>(
Expression.MemberInit(
Expression.New((ConstructorInfo)typeof(TSource).GetConstructor(new Type[] { }), new Expression[0]),
binding.ToArray()
),
new ParameterExpression[] { ps }
);
return source.Select(lambda);
}
}
ИЕ>В результате 2х дней размышлений, родилось общее простое решение заменитель Select, которое позволяет загружать вместе с обычными полями, также первый уровень ассоциаций. Работает он также как показано в примере, просто переприсваивая все свойства. Не проверено скорость работы, вероятно эффективней было бы кешировать эти лямбды при загрузке, для каждого класса.
public static class Extensions
{
public static IQueryable<TSource> SelectAssoc<TSource>(this IQueryable<TSource> source)
{
ParameterExpression ps = Expression.Parameter(typeof(TSource), "p");
List<MemberBinding> binding = new List<MemberBinding>();
var props = typeof(TSource).GetProperties();
foreach (var prop in props)
{
if (prop.GetSetMethod() == null) continue;
binding.Add(
Expression.Bind(
prop.GetSetMethod(),
Expression.Property(ps, prop.GetGetMethod())
)
);
}
var lambda = Expression.Lambda<Func<TSource, TSource>>(
Expression.MemberInit(
Expression.New((ConstructorInfo)typeof(TSource).GetConstructor(new Type[] { }), new Expression[0]),
binding.ToArray()
),
new ParameterExpression[] { ps }
);
return source.Select(lambda);
}
}
Уважаемый Игорь Евгеньевич!
Передо мной стоит сейчас аналогичная задача, но, увы, опыт не позволяет понять как использовать ваше решение. Не могли бы вы привести подробный пример применения?
Здравствуйте, GaroRobe, Вы писали:
GR>Уважаемый Игорь Евгеньевич!
GR>Передо мной стоит сейчас аналогичная задача, но, увы, опыт не позволяет понять как использовать ваше решение. Не могли бы вы привести подробный пример применения?
Очень просто. Данная конструкция автоматизирует по сути ручное написание следующего кода.
С помощью кода Вы получите подгруженные foreign key ключи. Кстати множественные ассоциации таким образом к сожалению не подгрузиш. А мой код упрощает этот путь тем что заменяет ручное написание следующим: