Представьте себе таблицу базы данных, которая выглядит следующим образом:
create table [dbo].[user]
(
id int IDENTITY(1,1),
username varchar(50) NOT NULL,
firstname varchar(20) NOT NULL,
lastname varchar(30) NOT NULL,
currentid int NULL,
processedby varchar(50) NOT NULL,
processeddate varchar(50) NOT NULL
processedaction varchar(50) NOT NULL
)
Что я хочу сделать, так это настроить NHibernate для загрузки его в мой объект пользователя, но я хочу только вернуть текущую версию объекта "пользователь". Я знаю, как сделать выбор SQL, чтобы сделать это самостоятельно, и мне кажется, что в nHibernate есть что-то с использованием триггеров и прослушивателей событий, но кто-нибудь может сказать мне, как реализовать репозиторий nHibernate, чтобы я мог:
- {Репозиторий} .GetCurrent (id) <- передать ему любой из идентификаторов, которые назначены любой из исторической или текущей записи, и вернуть текущий объект. </li>
- {Репозиторий} .Save (пользователь) <- Я хочу всегда вставлять изменения в новую строку, а затем обновлять старые версии, чтобы ссылаться на новый идентификатор. </li>
Редактировать
Итак, здесь есть некоторая путаница, и, возможно, я объяснил это неправильно ... Я пытаюсь сделать следующее: всегда возвращать текущую запись ...
Select uc.*
FROM User uo
JOIN User uc on uo.currentid=uc.id
WHERE uo.id==:id
Но я не хочу показывать «CurrentID» моей объектной модели, так как он не имеет отношения к остальной системе, ИМХО. В приведенном выше операторе SQL uo считается «исходным» набором объектов, а uc считается текущим объектом в системе.
Редактировать # 2:
Рассматривая это как возможное решение.
http://ayende.com/blog/4196/append-only-models-with-nhibernate
Я, честно говоря, схожу с ума, поскольку я думаю об этом отсталым. При этом способе запуска базы данных поле автоинкрементации должно быть полем версии, а поле "id" должно быть таким, какое бы значение автоинкрементатора не имело во время начальной вставки.
Ответ:
Я не хочу принимать ярость @ Фиро, и я не собираюсь снимать ее с него, так как он взял меня по правильному пути ..., с чем я столкнулся:
- Создан базовый родовой класс с двумя заданными типами.
а. тип идентификатора объекта
б. тип самого объекта.
- создать экземпляр всех классов.
- создать универсальный интерфейс класса IRepository с типом объекта для хранения / извлечения.
- создать абстрактный обобщенный класс с типом объекта для хранения / извлечения.
- создать конкретный класс реализации для каждого типа для хранения / извлечения.
внутри создания / обновления процедура выглядит так:
Type Commit(Type item)
{
var clone = item.DeepClone();
_Session.Evict(item);
clone.Id = 0;
clone.ProcessedDate = DateTime.Now;
if (clone.Action.HasValue)
{
if (clone.Action == ProcessedAction.Create)
clone.Action = ProcessedAction.Update;
}
else
{
clone.Action = ProcessedAction.Create;
}
clone.ProcessedBy = UserRepos.Where(u => u.Username == System.Threading.Thread.CurrentPrincipal.Identity.Name).First().Current;
var savedItem = (_Session.Merge(clone) as Type);
_Session.CreateQuery("UPDATE Type SET CurrentID = :newID where ID=:newID OR CurrentID=:oldID")
.SetParameter("newID", savedItem.Id)
.SetParameter("oldID", item.Id)
.ExecuteUpdate();
return savedItem;
}
В методе delete мы просто обновляем {object} .Action = ProcessedAction.Delete
Я хотел сделать это по-другому, но, понимая, что в конечном итоге нам нужно провести исторические сравнения, мы не смогли попросить nHibernate отфильтровать удаленные объекты, поскольку пользователи захотят это увидеть. Мы создадим бизнес-фасад, чтобы позаботиться об удаленных записях.
Опять же, большое спасибо @Firo за помощь в этом.
Итак, со всем этим я наконец могу сделать это:
var result = {Repository}.Where(obj => obj.Id == {objectID from caller}).FirstOrDefault();
if (result != null)
{
return result.Current;
}
else
{
return null;
}
и всегда возвращаю мой текущий объект для любого запрашивающего идентификатора. Надеюсь, это поможет кому-то, кто в моей ситуации.