Заменяет предложение в структуре базы данных - PullRequest
0 голосов
/ 18 февраля 2012

Представьте себе таблицу базы данных, которая выглядит следующим образом:

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" должно быть таким, какое бы значение автоинкрементатора не имело во время начальной вставки.


Ответ:

Я не хочу принимать ярость @ Фиро, и я не собираюсь снимать ее с него, так как он взял меня по правильному пути ..., с чем я столкнулся:

  1. Создан базовый родовой класс с двумя заданными типами. а. тип идентификатора объекта б. тип самого объекта.
  2. создать экземпляр всех классов.
  3. создать универсальный интерфейс класса IRepository с типом объекта для хранения / извлечения.
  4. создать абстрактный обобщенный класс с типом объекта для хранения / извлечения.
  5. создать конкретный класс реализации для каждого типа для хранения / извлечения.
  6. внутри создания / обновления процедура выглядит так:

    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;
    }
    
  7. В методе 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;
}

и всегда возвращаю мой текущий объект для любого запрашивающего идентификатора. Надеюсь, это поможет кому-то, кто в моей ситуации.

Ответы [ 2 ]

0 голосов
/ 20 февраля 2012

Вы можете указать NHibernate, какой именно SQL он должен генерировать при сохранении и загрузке сущности. Например, вы можете указать NHibernate использовать хранимую процедуру вместо простого оператора SQL. Если это вариант для вас, я могу уточнить свой ответ.

0 голосов
/ 20 февраля 2012

в отображении, если вы используете FluentNHibernate

public UserMap : ClassMap<User>
{
    public UserMap()
    {
        Where("id = currentid"); // always bring back the most recent
    }
}

// in Userrepository
public void Update(User user)
{
    var clone = user.Clone();
    session.Evict(user);  // to prevent flushing the changes
    var newId = session.Save(clone);
    session.CreateQuery("UPDATE User u SET u.currentid = :current")  // <-- hql
        .SetParameter("current", newId)
        .ExecuteUpdate();
}

objectgraphs намного сложнее с этим простым кодом. Затем я бы сделал одно из следующих действий:

  • используйте NHibernate.Envers для хранения информации об аудите для меня
  • явное создание новых объектов в BL-коде

Однажды я видел модель только для добавления, выполняющую что-то вроде следующего

// UserBase is there to ensure that all others referencing the User doesnt have to update because user properties changed
class UserBase
{
    public virtual int Id { get; set; }
    public virtual ICollection<PersonDetails> AllDetails { get; private set; }
    public virtual PersonDetails CurrentDetails
    {
        get { return _currentDetauils; }
        set { _currentDetauils = value; AllDetails.Add(value); }
    }

    // same as above
    public virtual ICollection<ConfigDetails> AllConfigs { get; set; }
}

class Order
{
    public virtual int Id { get; set; }
    public virtual UserBase User { get; set; }

    public virtual IList<OrderDetail> AllDetails { get; private set; }
    public virtual IList<OrderDetail> ActiveDetails { get; private set; }

    public virtual void Add(OrderDetail detail)
    {
        AllDetails.Add(detail);
        ActiveDetails.Add(detail);
    }
    public virtual void Delete(OrderDetail detail)
    {
        detail.Active = false;
        ActiveDetails.Remove(detail);
    }
}

class OrderDetail
{
    public virtual int Id { get; set; }
    public virtual Order Parent { get; set; }

    public virtual bool Active { get; set; }
}

class OrderMap : ClassMap<Order>
{
    public OrderMap()
    {
        HasMany(o => o.AllDetails);
        HasMany(o => o.ActiveDetails).Where("active=1");
    }
}

// somewhere
public void UpdateTaxCharge(OrderDetail detail, TaxCharge charge)
{
    var clone = detail.Clone();
    clone.TaxCharge = charge;
    detail.Order.Delete(detail);
    detail.Order.Add(clone);
}
...