Posted
about 13 years
ago
by
igor-booch <[email protected]>
Баг стабильно воспроизводится, но путь воспроизведения не тривиальный.
В кратце:
есть метод Search, в котором в
using (DbManager dbManager = new DbManager())
{
...
}
делается Linq запрос. К запросу в зависимости от параметров введенных
... [More]
пользователем динамически подсоединяются Where (делаю функционал поиска по БД): +1 параметр -> +1 Where.
Если сначала (после запуска приложения) выполнить Search с 2-ми параметрами (2 Where), потом второй параметр убрать (остается 1 Where) и еще раз выполнить Search, то получается Exception (запрос не может пропарситься в SQL):
Unable to cast object of type 'System.Linq.Expressions.ConstantExpression' to type 'System.Linq.Expressions.UnaryExpression'.
at lambda_method(Closure , Expression , Object[] )
at BLToolkit.Data.Linq.Query`1.SetParameters(Expression expr, Object[] parameters, Int32 idx) in D:\Projects\SandBox\BLToolkit\Data\Linq\Query.cs:line 355
at BLToolkit.Data.Linq.Query`1.SetCommand(IDataContext dataContext, Expression expr, Object[] parameters, Int32 idx) in D:\Projects\SandBox\BLToolkit\Data\Linq\Query.cs:line 347
at BLToolkit.Data.Linq.Query`1.<RunQuery>d__11.MoveNext() in D:\Projects\SandBox\BLToolkit\Data\Linq\Query.cs:line 327
at BLToolkit.Data.Linq.Query`1.<Map>d__63.MoveNext() in D:\Projects\SandBox\BLToolkit\Data\Linq\Query.cs:line 983
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Telda.Rusgidro.MonitoringObjectInformationSearch.ViewModels.MainViewModel.ExecuteSearchCommand(String commandParameter) in D:\Projects\SandBox\Telda.Rusgidro.MonitoringObjectInformationSearch\ViewModels\MainViewModel.cs:line 331
Эксепшен происходит в методе
void SetParameters(Expression expr, object[] parameters, int idx)
{
foreach (var p in Queries[idx].Parameters)
p.SqlParameter.Value = p.Accessor(expr, parameters);
}
Эксепшен вызывает получение p.Accessor(expr, parameters).
Такое впечатление, что происходит кэширование параметров запроса, которое BLToolkit не может переварить.
Linq запрос с 2-ми параметрами выглядит примерно так:
dbManager.GetTable<MonitoringObject>().Where(mo =>
dbManager.GetTable<MonitoringObject>()
.Join(
dbManager.GetTable<ObjectFeatures>(),
se => se.MonitoringObject.Id,
of => of.MonitoringObjectId,
(se, of) =>
new SearchEntry
{
MonitoringObject = se.MonitoringObject,
ObjectFeatures = of,
})
.Where(se => se.ObjectFeatures.Name.Contains("DF"))
.Where(se => se.ObjectFeatures.RegistryNumber.Contains("34"))
.Select(se => se.MonitoringObject.Id.Value)
.Contains(mo.Id.Value))
Результат парсинга Linq запрос'f с 2-ми Where выглядит примерно так:
-- Oracle.Rusgidro Odp Oracle
-- DECLARE :p1 String
-- DECLARE :p2 String
-- SET :p1 = '%DF%'
-- SET :p2 = '%34%'
SELECT
mo.Id
mo.Code,
mo.Name,
FROM
MonitoringObject mo
WHERE
EXISTS(
SELECT
*
FROM
(
SELECT
mo1.Id as c1
FROM
MonitoringObject mo1
INNER JOIN ObjectFeatures of1 ON mo1.Id = of1.MonitoringObjectId
WHERE
Upper(of1.Name) LIKE :p1 ESCAPE '~' AND Upper(of1.RegistryNumber) LIKE :p2 ESCAPE '~'
) t1
WHERE
t1.c1 = mo.Id
)
Причем часть запроса помеченная курсивом парсится в SQL нормально при любых сценариях:
-- Oracle.Rusgidro Odp Oracle
-- DECLARE :p1 String
-- SET :p1 = '%DF%'
SELECT
mo.Id
FROM
MonitoringObject mo
INNER JOIN ObjectFeatures of1 ON mo.Id = of1.MonitoringObjectId
WHERE
Upper(of1.Name) LIKE :p1 ESCAPE '~'
Если сначала (после запуска приложения) выполнить метод Search с 1-им Where, то потом все работает как по маслу.
Я конечно нашел workaround, но я люблю BLToolKit и хочу чтобы в нем было по меньше багов. Так что workarounds можно не предлагать. [Less]
|
Posted
about 13 years
ago
by
10der <[email protected]>
Добрый день.
Есть цель легко получать результат выполнения процедуры (exec @Issue = dbo.ProcName)
С ходу не получилось
Подскажите мысли, если не трудно.
public class CurrencyManager : BusinessManagerBase<CurrencyManager>
{
... [More]
public CurrencyManager()
{
}
private CurrencyAccessor Accessor
{
get
{
return this.CreateDataAccessInstance<CurrencyAccessor>();
}
}
public GetCurrencyRatesResponse GetCurrencyRates()
{
var a = Accessor;
var x = a.GetCurrencyRates();
if (x != null) {}
if (a.err != 0) {}
}
}
[........]
public abstract class MyAccessor : SimpleAccessor
{
public int err = -1;
// за такой изврат нужно убивать...
protected override void Dispose(DbManager dbManager)
{
err = (int)dbManager.Parameter("@RETURN_VALUE").Value;
base.Dispose(dbManager);
}
}
public abstract class CurrencyAccessor : MyAccessor
{
[SprocName("dbo.p_GetCurrencyRates")]
public abstract List<ExchangeRateInfo> GetCurrencyRates();
}
Есть обходной вариант, но почему то прописывать каждый раз в процедуре доп параметр, которого нет в процах, да и еще с созданием класса ошибки, меня не прётЪ...
public abstract List<ExchangeRateInfo> GetCurrencyRates([Direction.ReturnValue("Error")] SQLExecReturnValue Error);
[...]
SQLExecReturnValue ret = new SQLExecReturnValue();
var x = Accessor.GetCurrencyRates(ret).ToArray();
if (x != null) {}
Спасибо! [Less]
|
Posted
about 13 years
ago
by
Aikin <[email protected]>
Доброе время суток,
Требуется перевести на линкю такой запрос:
SELECT Count(*) as Count, Avg(Hits) as AvgHits, Avg(TotalTime) as AvgTime
FROM Visitor
Как это можно сделать на linq+BLToolkit
В интернетах подсказывают, что можно
... [More]
делать группировку по константе:
var summary = (from v in Visitors
group v by 1 into g
select new {
Visitors = g.Count(),
AvgPages = g.Average(v => v.Hits),
AvgTime = g.Average(v => v.TotalTime)
}).First();
Вот что генерит Toolkit:
SELECT TOP (1)
Count(*) as [c1],
Avg([v].[Hits]) as [c2],
Avg([v].[TotalTime]) as [c3]
FROM
[Visitor] [v]
GROUP BY 1
На который сервер ругается: Each GROUP BY expression must contain at least one column that is not an outer reference.
Его понять можно. Ему не нравится последняя строчка. Вот если бы ее не было...
Может есть еще какой способ добиться нужного мне поведения?
База MS SQL Server, BLToolkit.v4
СУВ, Aikin... << RSDN@Home 1.2.0 alpha 4 rev. 1476>> [Less]
|
Posted
about 13 years
ago
by
MozgC <[email protected]>
Ребят, уже больше часа вожусь, не могу перевести запрос с SQL на LINQ.
Вкратце задача: найти вес (физический и объемный) коробок, в которых упакованы запчасти из такого-то счёта.
План поиска: находим запчасти из нужного счёта -> находим в
... [More]
каких коробках они упакованы -> находим суммарный вес этих коробок
База: mysql
Рабочий SQL:
SELECT
SUM(Weight), SUM(VolumeWeight)
FROM
(SELECT
b.Weight, b.Length * b.Width * b.Height / 6000 AS VolumeWeight # объемный вес груза считается как длина*ширина*высота/6000
FROM
parts p # это типа order lines
INNER JOIN boxes b ON (b.InternalBoxN = p.InternalBoxN)
WHERE
p.Customer = 'GAZPROM' AND p.CustomerInvoiceN = 111
GROUP BY
b.BoxN) AS tmp;
Попытки перевести на Linq:
var boxes =
from p in db.Parts
join b in db.Boxes on p.InternalBoxN equals b.InternalBoxN
where p.Customer == customerName && p.CustomerInvoiceN == customerInvoiceN
group b by new { b.BoxN, b.Weight, VolumeWeight = (decimal)(b.Length*b.Width*b.Height) / 6000 } into g // группируем по этим полям чтобы можно было их взять в селекте
select new { g.Key.BoxN, g.Key.Weight, g.Key.VolumeWeight };
var q =
from b in boxes
group b by b.BoxN into g // используем группировку чтобы в селекте можно было использовать суммы по разным полям
select new { Weight = g.Sum(b => b.Weight), VolumeWeight = g.Sum(b => b.VolumeWeight) };
var result = q.First();
return new Tuple<decimal, decimal>(result.Weight, result.VolumeWeight);
Результирующий sql:
SELECT
Sum(b.Weight) as c1,
Sum(Cast((b.Length * b.Width * b.Height) as Decimal(10,0)) / 6000) as c2
FROM
parts p
INNER JOIN boxes b ON p.InternalBoxN = b.InternalBoxN
WHERE
p.Customer = 'GAZPROM' AND p.CustomerInvoiceN = 111
GROUP BY
b.BoxN
LIMIT 1
Запрос делает совсем не то, что хотелось бы
Еще пробовал так, получил исключение:
var boxes =
from p in db.Parts
join b in db.Boxes on p.InternalBoxN equals b.InternalBoxN
where p.Customer == customerName && p.CustomerInvoiceN == customerInvoiceN
group b by b.BoxN into g
select g.First();
var q = from b in boxes
group b by b.BoxN into g
select new { Weight = g.Sum(b => b.Weight), VolumeWeight = g.Sum(b => (decimal)(b.Length * b.Width * b.Height) / 6000) };
var result = q.First(); // NotImplementedException from BLToolkit.Data.Linq.Builder.GroupByBuilder
return new Tuple<decimal, decimal>(result.Weight, result.VolumeWeight);
help.. [Less]
|
Posted
about 13 years
ago
by
mad_net <[email protected]>
Добрый день.
У меня имеется некая система позволяющая автоматически сохранять изменения свойств сущностей. Все на тестах простых работало. Потом когда написали много полезного кода и отправли проект на тестирование начали возникать ошибки ствязанные
... [More]
с тем, что на сущностях (в остновном где есть нуловые вторичные ключи) не сохраняются значения свойств с типом int?. Ошибка возникает на столько редко, что единичные тесты ничего не показывают (где-то раз на 3000 итераций), и это очень печально потому что простым дебагом нельзя добиться 100% воспроизведения ошибки. Может кто-то сталкивался с подобными проблемами, надеюсь знающие люди помогут.
Полного кода всех модулей позволяющего воспроизвести ошибку не могу выложить в топик, но прилагаю код тех методов где я использую BLToolkit и где возникает ошибка.
Часть кода которая производит апдейт сощностей, здесь важным является формирование sql запроса (метод GetUpdQuery(_entity,out strlog)
var dbm = _dbManager.DbManager;
var query = dbm.GetTable<T>().Where(e => e.Key == _entity.Key).GetUpdQuery(_entity,out strlog);
if (query != null)
{
query.Update();
Log.InfoFormat("Entity was updated in db ({0}[{1}])", _entity.TypeKey, _entity.Key);
if (_entity.TypeKey == TypeKeys.ArmorPart)
{
Log.Info("DBParticle.ArmorUpdated - " strlog);
Log.Fatal("LastUqery:{0}", dbm.LastQuery);
}
}
Сам метод формирующий запрос
public static IUpdateable<T> GetUpdQuery<T>(this IQueryable<T> query, T entity, out string strLog)where T : class, IGPropertyContainer
{
strLog = string.Format("GetUpdQuery({0}[{1}]) fields: ",entity.TypeKey,entity.Key);
IUpdateable<T> updQuery = null;// new Extensions.Updateable<T>() { Query = query };
for (int i = 0; i < entity.Properties.Count; i )
{
IGProperty prop = entity.Properties[i];
if (!((IEditable)prop).IsDirty) continue;
var t = TypeAccessor.GetAccessor(typeof(T));
var ma = ExprMemberAccessor.GetMemberAccessor(t, prop.Name);
var metaMember = ExtMetadataHelper.GetMetaMemberAccessor(ma);
var attr1 = metaMember.GetAttribute<SqlIgnoreAttribute>();
if (attr1 != null) continue;
var attr2 = metaMember.GetAttribute<NonUpdatableAttribute>();
if (attr2 != null) continue;
strLog = string.Format("{0}={1}, ", prop.Name,prop.Value);
if (updQuery == null)
updQuery = query.AddSet(prop);
else
updQuery = updQuery.AddSet(prop);
}
return updQuery;
}
if (updQuery == null)
updQuery = query.AddSet(prop);
else
updQuery = updQuery.AddSet(prop);
- такой код связан сособенностями реализации в BLToolkit для разных интефейсов для IQueryable<T> и IUpdateable<T>
Собственно сами методы которые добавляют выражение Set в запрос для разных сорсов IQueryable<T> и IUpdateable<T>
public static IUpdateable<T> AddSet<T>(this IUpdateable<T> query, IGProperty prop)
where T : class, IGPropertyContainer
{
ParameterExpression entityParam = Expression.Parameter(typeof(T), "entity");
IEnumerable<MethodInfo> methods =
from method in typeof(Extensions).GetMethods(BindingFlags.Public | BindingFlags.Static)
let parameters = method.GetParameters()
let genParams = method.GetGenericArguments()
where method.Name == "Set" &&
method.ContainsGenericParameters &&
parameters.Length == 3 &&
parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(IUpdateable<>) &&
parameters[2].ParameterType.BaseType == typeof(object)
select method;
MethodInfo miSet = methods.FirstOrDefault().MakeGenericMethod(new[] { typeof(T), prop.ValueType });
MemberExpression propExpr = Expression.PropertyOrField(entityParam, prop.Name);
Expression propertyAccess = Expression.Lambda(propExpr, entityParam);
var result = (IUpdateable<T>)miSet.Invoke(null, new[] { query, propertyAccess, prop.Value });
return result;
}
public static IUpdateable<T> AddSet<T>(this IQueryable<T> query, IGProperty prop)
where T : class, IGPropertyContainer
{
ParameterExpression entityParam = Expression.Parameter(typeof(T), "entity");
IEnumerable<MethodInfo> methods =
from method in typeof(Extensions).GetMethods(BindingFlags.Public | BindingFlags.Static)
let parameters = method.GetParameters()
let genParams = method.GetGenericArguments()
where method.Name == "Set" &&
method.ContainsGenericParameters &&
parameters.Length == 3 &&
parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(IQueryable<>) &&
parameters[2].ParameterType.BaseType == typeof(object)
select method;
MethodInfo miSet = methods.FirstOrDefault().MakeGenericMethod(new[] { typeof(T), prop.ValueType });
MemberExpression propExpr = Expression.PropertyOrField(entityParam, prop.Name);
Expression propertyAccess = Expression.Lambda(propExpr, entityParam);
var result = (IUpdateable<T>)miSet.Invoke(null, new[] { query, propertyAccess, prop.Value });
return result;
}
эти методы отличаются лиш одной строчкой
parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(IUpdateable<>) &&.
Код метода теста который воспроизводит ошибку
public void UpdateOneNullableIntPropertyTest(int index)
{
var dbm = new DBAccess.GenericDBManager<TestEntity>();
var testEntity = dbm.Table.FirstOrDefault(te => te.StringField == "TestString");
var intValue = (new Random()).Next(1000);
//testEntity.IntField = intValue;
if ((intValue % 2) == 1)
testEntity.IntNullField = null;
else
testEntity.IntNullField = testEntity.IntField;
DBParticle<TestEntity> dbParticle = new DBParticle<TestEntity>(testEntity, dbm);
dbParticle.Store();
Console.Out.WriteLine(dbm.DbManager.LastQuery);
Debug.WriteLine(dbm.DbManager.LastQuery);
var existendEntity = Get<TestEntity>(testEntity.Key);
Assert.IsTrue(testEntity.Equals(existendEntity),"Iteration=" intValue.ToString());
}
если раскомментировать строчку
//testEntity.IntField = intValue;
ошибка не воспроизводится.
Еще приложу две вырезки из лога когда одна и таже сущность сохранялась в базу с двумя измененными свойствами и с одним.
К примеру вот часть кода
//armorPart.CurrentDurability--; armorPart.CurrentDurability ;
armorPart.ArmorID = Key;
если раскоментировать первую строчку лог последнего sql запроса выдает результат
UPDATE
[e]
SET
[ArmorID] = @p1,
[CurrentDurability] = 48
FROM
[ConcreteArmorParts] [e]
WHERE
[e].[CArmorPartID] = @Key1
при закоментированной первой строчке sql имеет следующий вид
UPDATE
[e]
SET
[ArmorID] = NULL
FROM
[ConcreteArmorParts] [e]
WHERE
[e].[CArmorPartID] = @Key1
Извините за столь обширное описание проблемы. [Less]
|
Posted
about 13 years
ago
by
kkolyan <[email protected]>
добавил в проект MySql.ttinclude, BLToolkit.ttinclude, создал tt файл, сгенерировал класс с моделями
пытаюсь выполнить код
private static void tets1()
{
var db = new DataModel();
var ll = db.adminmenu;
... [More]
foreach (var item in ll)
{
Console.WriteLine(item.Title);
}
}
static void test2()
{
using (var db = new DbManager("MySql"))
{
var query = new SqlQuery<adminmenu>();
foreach (var item in query.SelectAll())
{
Console.WriteLine(item.Title);
}
}
}
не подключается к базе, как правильно указать конекшен, чтобы хоть что то вывело на экран
в app.config добавил конекшен стринг
<connectionStrings>
<add name="MySql" connectionString="Server=localhost;Port=3306;Database=***;Uid=root;pwd=***;" providerName="MySql.Data.MySqlClient"/>
</connectionStrings> [Less]
|
Posted
about 13 years
ago
by
AK107 <[email protected]>
Есть запросы, анпример на вставку, вида:
messageId = ... ;
db.GetTable<User>().Insert(db.GetTable<UserMessage>(), x => new Entities.UserMessage
{
UserId = x.Id,
MessageId = messageId,
... [More]
});
они генерируют такой sql
INSERT INTO t_user_message
(
user_id,
message_id
)
SELECT
t1.user_id as Id,
459 as c1
FROM
t_user t1
таким образом выделенное не передается как параметр sql запроса а идет как часть sql текста.
вопрос: почему?
есть еще ряд запросов где генерируются константы в тексте, например в таком:
db.GetTable<Message>().Skip(from).Take(size)
sql запрос будет выглядеть примерно так:
...
) t
WHERE
ROWNUM <= 120
) t5
WHERE
t5.rn > 110
з.ы. эт я к чему спрашиваю: для БД по идее все запросы выглядят разные т.к. не используются парамтры со всеми вытекающими полными разборами и прочее... [Less]
|
Posted
about 13 years
ago
by
_Budda_ <[email protected]>
Следующий код (C#.NET 4.0, BLToolkit 4.1, MySql 5.1):
var v = from c in db.GetTable<Country>()
join t0 in db.GetTable<Team>() on c.Id equals t0.CountryId into t1
from team in t1.DefaultIfEmpty()
group team
... [More]
by c.Id into teamsGrouped
select new CountryTeamsInfo
{
CountryId = teamsGrouped.Key,
TeamsTotal = teamsGrouped.Count(),
// TeamsWithoutOwnerFree = teamsGrouped.Count(t => t.OwnerId==0)
}
;
List<CountryTeamsInfo> res = v.ToList();
Генерирует следующую кверю:
SELECT c.Id, Count(*) as c1
FROM countries c
LEFT JOIN teams t1 ON c.Id = t1.Country
GROUP BY c.Id
Фактически, мне нужно получить не только количество объектов в присоединенной таблице, но также число объектов, у которых нет владельцев (OwnerId==0). В теории, мне должно было бы быть достаточно раскомментировать строку, которая это вычисляет, но выполнение такого кода вызывает ошибку:
The given key was not present in the dictionary
При этом, кверя не попадает в профайлер базы данных, и я не могу понять, что именно генерируется.
Аналогичный код, примененный к такой же структуре таблиц MSSQL через Entity Framework работает как положенно.
Подскажите, пожалуйста, в чем проблема: я что-то делаю не так (как правильнО)? или бага внутри Bltoolkit'а (реально ли пофиксить)?
Заранее большое спасибо!
Я нашел, как обойти проблему, но получилось через Ж:
[c#]
var v = db.GetTable<Country>().Where(country => country.Allowed)
.GroupJoin(
db.GetTable<Team>(),
country => country.Id,
team => team.CountryId,
(country, teams) => new CountryTeamsInfo
{
CountryId = country.Id,
TeamsTotal = teams.Count(),
TeamsWithoutOwnerFree = teams.Count(t => t.OwnerId != 0),
}
).GroupJoin(
db.GetTable<Team>().Where(te=>te.OwnerId==0),
cti => cti.CountryId,
team => team.CountryId,
(cti, teams) => new CountryTeamsInfo
{
CountryId = cti.CountryId,
TeamsTotal = cti.TeamsTotal,
TeamsWithoutOwnerFree = teams.Count(t => t.OwnerId != 0),
}
)
;
[/ccode]
SELECT
cti.Id as Id1,
cti.c1 as c11,
(
SELECT
Count(*)
FROM
teams te
WHERE
cti.Id = te.Country AND te.User = 0
) as c2
FROM
(
SELECT
country.Id,
(
SELECT
Count(*)
FROM
teams t1
WHERE
country.Id = t1.Country
) as c1
FROM
countries country
WHERE
country.allow [Less]
|
Posted
about 13 years
ago
by
MuxMux <[email protected]>
Всем доброго времени суток!
Есть вот такой linq запрос:
from sv in db.GetTable<SectionValue>()
join mo in db.GetTable<MonitoringObject>() on sv.MonitoringObjectId equals mo.Id into gr
from mo in gr.DefaultIfEmpty()
select select
... [More]
new {sv, mo};
Никаких специфических полей у этих сущностей нет. Единственное, у сущности
MonitoringObject есть строковое поле "Code". В принципе тоже ничего особенного
в этом свойстве нет. В базе (Oracle) оно объявлено как Nullable.
Вся странность результата запроса заключается в том, что MonitoringObject-ы
(которые соответствуют существующим SectionValue) с не заполненным полем "Code"
выводятся как null. Причем такая странная реакция только на поле "Code"
(с другими названиями все работает должным образом).
При этом если применить сгенерированный SQL запрос напрямую к таблицам БД,
то результат будет правильный.
Более того такая ситуация только с linq-ым LEFT JOIN. Linq запрос
с INNER JOIN работает верно.
from sv in db.GetTable<SectionValue>()
join mo in db.GetTable<MonitoringObject>() on sv.MonitoringObjectId equals mo.Id
select select new {sv, mo};
Возможно, слово "Code" где-то зарезервировано в самом ORM.
Хотелось бы понять, в чем дело, и возможно ли исправить ситуацию
малой кровью.
Заранее спасибо. [Less]
|
Posted
about 13 years
ago
by
mk76 <[email protected]>
class objA {
int ID {get;set;}
string Name {get;set;}
int b_ID {get;set;}
[Associtiation(ThisKey = "b_ID", OtherKey = "ID")]
objB B {get;set;}
int c_ID {get;set;}
[Associtiation(ThisKey = "c_ID", OtherKey = "ID")]
... [More]
objC C {get;set;}
List<objX> ListOfX{get;set;}
...
}
class objB{
int ID {get;set;}
string Name {get;set;}
...
}
class objC{
int ID {get;set;}
string Name {get;set;}
}
...
хочется упростить написание загрузки ассоциаций (напр B и C в классе objA)
по документации маппинг загрузка ассоц. свойств выглядит как :
from a in GetTable<objA>()
seleсt new objA(a){B=a.B, C = a.C};
минусы кот видны сразу же — создается два инстанса objA
для каждого класса надо писать два конструктора — пустой и с копированием полей
или писать простыню типа new objA(){Id= a.ID,Name = a.Name, b_ID = a.b_ID, B = a.B, ......} — можно сразу застрелиться если много классов в модели , и в каждом классе тоже не по 2-3 свойства
попытки написать простеький extension типа
T MapProp<T>(this T item, Expression<Func<T,object>> map, object value){
string mapname = ((MemberExpression)map.Body).Member.Name;
typeof(T).Property(mapname).SetValue(item,value);
return item;
}
c соответсвующим вызовом
from a in GetTable<objA>()
select a.MapProp((x)=>x.B , a.B)
думалось что все получится и будет щастьЕ — не сложилось — BLT попытался видимо все это запихнуть в сиквел и соотвественно сломался на построение дерева выражений
вопрос в студию — можно ли с минимальным кол-вом телодвижений, не изобретая велосипед сделать что нибудь подобное, может быть в стиле
EntityFrameworka :
from a in db.objA
select a
.Include(x=>x.B)
.Include(x=>x.C.D.E) — сдесь тоже грузятся все вложенные свойва
Просто может кто то озадачивался написанием с помощью BLT ,что то вроде UnitOfWork напр такого плана
class DAL<T> {
List<T> Select<T>(Predicate filter, "Выражение для указания загрузки вложенных св-ва" includeProps )
{
using (dbManager ){
// какой нибудь кусок бизнес логики
...
// может быть часть конечного запроса
var qry = from a in db.A select a where a.SomeDate> DateTime.Now.AddYear(-1);
//встраиваем фильтр напр так
qry = qry.Where(filter);
// загрузка ассоциаций
//всегда грузим свойсво Z
qry = qry.Include(x=>x.Z);
//грузим по требованию
foreach (var i in includeProps )
qry = qry.Include(i)
return qry.ToList()
}
}
}
соответсвенно на клиенте можно было бы использовать как например
1. DAL<SomeData>Select( (sd)=>sd.Number>10 , "Prop1;Prop2;Prop3")
2. DAL<SomeData>Select( (sd)=>sd.Number>10 , (sd)=>sd.Prop1, (sd)=>sd.Prop2, (sd)=>sd.ListPropA,
(при этом точно зная что данные только за последний год , что поле Z всегда загужено — указаи его или нет)
может у кого то есть мысли по поводу как это попроще организовать ? [Less]
|