Хочу предложить на суд свою реализацию для работы с вложенными объектами на BLT. http://rsdn.ru/File/58558/Person_on_BLT.rar
На форуме много споров, но конкретного законченного решения я не нашел.
Решение основано на справочниках, которые загружаются по мере необходимости и по истечению заданного таймаута выгружаются из памяти. В общем смотрите.....
Так же предлагаю совместными усилиями улучшить это решение.
Сразу скажу, что в BLT я новичок, так что не судите строго. Хочется совместно разобраться как лучше реализовать основу, для дальнейшей своей работы, а так же помочь ищущим найти решение.
Пишите, пожалуйста, свои пожелания, предложиния и замечания сюда, будем обсуждать.
Здравствуйте, IT, Вы писали:
IT>Какую проблему решает данное решение?
Проблему размножения сушьностей.
Person p1 = SomeAccessor.SelectByKey(1);
Person p2 = SomeAccessor.SelectByKey(1);
Assert.ReferenceEquals(p1, p2);
Смысл в том, что если один и тот же объект поднимается с базы несколько раз, то вместо копии нужно вернуть оригинал.
Если это достижимо, то все танцы вокруг master-slaves ака order-details решаются сами собой.
Но тут есть куча проблем: например, как решить, что этот один и тот же объект или всё-таки разные? Как узнать, что объект уже никому не нужен и его можно выкинуть из кеша? Как одновременно свести к минимуму использование памяти и не потерять при этом в скорости? И ещё куча
В принципе, всё это так или иначе решается. Правда исключительно путём добавления разного рода ограничений.
В частности, в этом Решении жизнено необходимо, чтобы у каждого объекта в базе был неизменяемый primary key типа Int32.
Кроме того, объектов в базе должно быть очень мало, т.к. все таблицы целиком считываются из базы и кешируются в памяти слоя бизнес логики.
Зато можно делать так:
public abstract class Person
{
[NullValue(0)]
public abstract int CityID { get; set; }
[MapIgnore]
public City City {
get { return (City)DictionaryManager.GetInstance()[typeof(City)][CityID]; }
set { CityID = value.ID; }
}
}
Бредовая идея
В принципе, можно заложить в BLToolkit основу для master-slave логики. Т.е. написать некий RelationAttribute, и добавить в DataAcessorBase пару методов, кидающих NotSupportedException. Тогда конечные пользователи смогит прикрутить к этой системе какие им угодно потроха.
public abstract class Person : SomeBase
{
[Relation("CityID")] // Полный список полей составляющих PKpublic abstract City City
{
get; // Идём туда, не знаю куда с PK и получаем объект или null.set; // Получаем объект или null и мапим его PK на заданные поля.
}
}
Но тут есть одна проблема: каждый объект типа Person (или SomeBase) должен быть связан с каким либо DataAccessor'ом. Хочется сделать всё просто, но в то же время гибко.
Здравствуйте, b0bi, Вы писали:
B>Решение основано на справочниках, которые загружаются по мере необходимости и по истечению заданного таймаута выгружаются из памяти. В общем смотрите.....
Хм... Знаете, как называется первый по алфавиту файл в исходниках BLToolkit?
Aspects\CacheAspect.cs
Соответственно, первый unit-test называется
Aspects\CacheAspectTest.cs
Этот аспект занимается кешированием результатов вызова методов. Например:
public abstract class SomeAccessor : DataAccessor
{
[NoInstance]
public abstract Dictionary<int, City> Cities
{
[Cache(36000000)] // 10 мин
[SqlQuery("SELECT * FROM Cities")]
get;
}
}
[Test]
public void CacheTest()
{
Dictionary<int, City> dic = _da.Cities;
Assert.AreEqual("Москва", dic[0].Name);
}
Согласен что это не панацея, не очень универсально. Этот вариант можно использовать для загрузки объектов из небольших таблиц (простейших справочников, типа "Города"), ну a то, что сложнее — ручками. А ведь по большей части справочники в БД, это как правило не большие таблицы (хотя случаи бывают разные), и такой подход экономит кучу времени.
БП>как решить, что этот один и тот же объект или всё-таки разные?
Конечно справочник должен иметь неизменяемый primary key типа Int32, объект не имеющий PK здесь никак не получится использовать.
БП>Как узнать, что объект уже никому не нужен и его можно выкинуть из кеша?
Таймаут решает эту проблемму.
БП>Как одновременно свести к минимуму использование памяти и не потерять при этом в скорости?
Только не большие справочники........ Действительно, это серьёзное ограничение.
БП>В принципе, всё это так или иначе решается. Правда исключительно путём добавления разного рода ограничений. БП>В частности, в этом Решении жизнено необходимо, чтобы у каждого объекта в базе был неизменяемый primary key типа Int32. БП>Кроме того, объектов в базе должно быть очень мало, т.к. все таблицы целиком считываются из базы и кешируются в памяти слоя бизнес логики.
Собственно, вы же на всё это и ответили. Со всем согласен. ...... остальное ручками......
БП>
Бредовая идея
...
БП>Но тут есть одна проблема: каждый объект типа Person (или SomeBase) должен быть связан с каким либо DataAccessor'ом. Хочется сделать всё просто, но в то же время гибко.
Было бы неплохо, действительно облегчило бы жизнь. Сейчас ведь приходится делать тоже более сложными способами.
Согласен что это не панацея, не очень универсально. Этот вариант можно использовать для загрузки объектов из небольших таблиц (простейших справочников, типа "Города"), ну a то, что сложнее — ручками. А ведь по большей части справочники в БД, это как правило не большие таблицы (хотя случаи бывают разные), и такой подход экономит кучу времени.
БП>как решить, что этот один и тот же объект или всё-таки разные?
Конечно справочник должен иметь неизменяемый primary key типа Int32, объект не имеющий PK здесь никак не получится использовать.
БП>Как узнать, что объект уже никому не нужен и его можно выкинуть из кеша?
Таймаут решает эту проблемму.
БП>Как одновременно свести к минимуму использование памяти и не потерять при этом в скорости?
Только не большие справочники........ Действительно, это серьёзное ограничение.
БП>В принципе, всё это так или иначе решается. Правда исключительно путём добавления разного рода ограничений. БП>В частности, в этом Решении жизнено необходимо, чтобы у каждого объекта в базе был неизменяемый primary key типа Int32. БП>Кроме того, объектов в базе должно быть очень мало, т.к. все таблицы целиком считываются из базы и кешируются в памяти слоя бизнес логики.
Собственно, вы же на всё это и ответили. Со всем согласен. ...... остальное ручками......
БП>Бредовая идея
...
БП>Но тут есть одна проблема: каждый объект типа Person (или SomeBase) должен быть связан с каким либо DataAccessor'ом. Хочется сделать всё просто, но в то же время гибко.
Было бы неплохо, действительно облегчило бы жизнь. Сейчас ведь приходится делать тоже самое более сложными способами.
Хочется сделать всё просто, но в то же время гибко.
Хранилище объектов?
Проблема в том, что решение этой задачи связано с введением множества ограничений и неоптимальностей. Если есть желание обсудить эту задачу, то начинать нужно именно с их обсуждения.
Если нам не помогут, то мы тоже никого не пощадим.
IT>Проблема в том, что решение этой задачи связано с введением множества ограничений и неоптимальностей. Если есть желание обсудить эту задачу, то начинать нужно именно с их обсуждения.
На ваш взгляд, какие недостатки у предложенного решения, кроме сказанного выше.
Предлагаю начать обсуждение с проблеммы "Как одновременно свести к минимуму использование памяти и не потерять при этом в скорости?"
Как вариант, можно загружать не целиком объекты, а только те поля, которые считаешь нужным....... А ещё можно записи подгружать по одной, по мере необходимости, но в этом случае произодительность страдает.
>БП Хочется сделать всё просто, но в то же время гибко.
А что если не кидать NotSupportedException, когда пользователь не прикрутил DataAccessor'у потроха, а самим пытаться достать данные, ведь всё для этого есть.