Nhibernate标准:“选择最大值(id)…”

Nhibernate标准:“选择最大值(id)…”,nhibernate,tsql,icriteria,Nhibernate,Tsql,Icriteria,我可以使用条件执行t-sql命令来选择表中某列的最大值吗 '从客户中选择@cus_id=maxid+1' 助教 OllieMaxid+1是生成ID的一种非常糟糕的方法。如果这是您的目标,请找到另一种生成ID的方法 编辑:在回答LnDCobra时: 这很糟糕,因为在插入时很难确保得到的maxid仍然是maxid。如果另一个进程插入一行,则插入将具有相同的id,并且插入将失败。或者,相反,如果先插入,则另一个进程的插入将失败 为了防止这种情况发生,您必须防止任何其他插入/使get和后续插入原子化,这

我可以使用条件执行t-sql命令来选择表中某列的最大值吗

'从客户中选择@cus_id=maxid+1'

助教


Ollie

Maxid+1是生成ID的一种非常糟糕的方法。如果这是您的目标,请找到另一种生成ID的方法

编辑:在回答LnDCobra时:

这很糟糕,因为在插入时很难确保得到的maxid仍然是maxid。如果另一个进程插入一行,则插入将具有相同的id,并且插入将失败。或者,相反,如果先插入,则另一个进程的插入将失败

为了防止这种情况发生,您必须防止任何其他插入/使get和后续插入原子化,这通常意味着锁定表,这将影响性能

如果您只锁定写操作,那么另一个进程将获得maxid,这与您获得的maxid相同。如果您插入并释放锁,它将插入一个重复的id并失败。或者它也试图锁定,在这种情况下,它会等待你。如果你也锁定了reads,那么每个人都在等你。如果它还锁定了写操作,那么它不会插入重复的id,但会等待您的读写操作

它打破了封装:您应该让rdbms找出它的ID,而不是连接到它的客户端程序

一般而言,该战略将: *中断 *需要一堆管道代码才能使其工作 *显著降低性能 *还是全部三个

与仅使用RDBMS的内置序列或生成的自动增量ID相比,它将更慢、更不健壮,并且需要更难维护的代码。

使用:


最好的方法是在表中添加额外的序列。 您可以在其中维护序列目标和值

public class Sequence : Entity
{

    public virtual long? OwnerId { get; set; }

    public virtual SequenceTarget SequenceTarget { get; set; }

    public virtual bool IsLocked { get; set; }

    public virtual long Value { get; set; }

    public void GenerateNextValue()
    {
        Value++;
    }

}

public class SequenceTarget : Entity
{

    public virtual string Name { get; set; }

}

public long GetNewSequenceValueForZZZZ(long ZZZZId)
{
    var target =
        Session
        .QueryOver<SequenceTarget>()
        .Where(st => st.Name == "DocNumber")
        .SingleOrDefault();

    if (target == null)
    {
        throw new EntityNotFoundException(typeof(SequenceTarget));
    }

    return GetNewSequenceValue(ZZZZId, target);
}

protected long GetNewSequenceValue(long? ownerId, SequenceTarget target)
{
    var seqQry =
       Session
       .QueryOver<Sequence>()
       .Where(seq => seq.SequenceTarget == target);
    if (ownerId.HasValue)
    {
       seqQry.Where(seq => seq.OwnerId == ownerId.Value);
    }

    var sequence = seqQry.SingleOrDefault();

    if (sequence == null)
    {
       throw new EntityNotFoundException(typeof(Sequence));
    }

    // re-read sequence, if it was in session
    Session.Refresh(sequence);

    // update IsLocked field, so we acuire lock on record
    // configure dynamic update , so only 1 field is being updated
    sequence.IsLocked = !sequence.IsLocked;
    Session.Update(sequence);
    // force update to db
    Session.Flush();
    // now we gained block - re-read record.
    Session.Refresh(sequence);

    // generate new value
    sequence.GenerateNextValue();
    // set back dummy filed
    sequence.IsLocked = !sequence.IsLocked;
    // update sequence & force changes to DB
    Session.Update(sequence);
    Session.Flush();

    return sequence.Value;
}

OwnerId-当您需要基于某种所有者为同一实体维护不同的序列时。例如,您需要为合同中的文档维护编号,那么OwnerId将是=contractId

此表达式的返回类型是什么?一个对象。可以使用UniqueResult重载将其强制转换为特定类型。在这种情况下,你会希望UniqueResult将其转换为整数。有人能给我指出正确的方向,为什么不使用它来生成id,如果是的话,还有更好的方法。。。?
public class Sequence : Entity
{

    public virtual long? OwnerId { get; set; }

    public virtual SequenceTarget SequenceTarget { get; set; }

    public virtual bool IsLocked { get; set; }

    public virtual long Value { get; set; }

    public void GenerateNextValue()
    {
        Value++;
    }

}

public class SequenceTarget : Entity
{

    public virtual string Name { get; set; }

}

public long GetNewSequenceValueForZZZZ(long ZZZZId)
{
    var target =
        Session
        .QueryOver<SequenceTarget>()
        .Where(st => st.Name == "DocNumber")
        .SingleOrDefault();

    if (target == null)
    {
        throw new EntityNotFoundException(typeof(SequenceTarget));
    }

    return GetNewSequenceValue(ZZZZId, target);
}

protected long GetNewSequenceValue(long? ownerId, SequenceTarget target)
{
    var seqQry =
       Session
       .QueryOver<Sequence>()
       .Where(seq => seq.SequenceTarget == target);
    if (ownerId.HasValue)
    {
       seqQry.Where(seq => seq.OwnerId == ownerId.Value);
    }

    var sequence = seqQry.SingleOrDefault();

    if (sequence == null)
    {
       throw new EntityNotFoundException(typeof(Sequence));
    }

    // re-read sequence, if it was in session
    Session.Refresh(sequence);

    // update IsLocked field, so we acuire lock on record
    // configure dynamic update , so only 1 field is being updated
    sequence.IsLocked = !sequence.IsLocked;
    Session.Update(sequence);
    // force update to db
    Session.Flush();
    // now we gained block - re-read record.
    Session.Refresh(sequence);

    // generate new value
    sequence.GenerateNextValue();
    // set back dummy filed
    sequence.IsLocked = !sequence.IsLocked;
    // update sequence & force changes to DB
    Session.Update(sequence);
    Session.Flush();

    return sequence.Value;
}