我可以使用Criteria执行t-sql命令来选择表中列的最大值吗?
'从客户
中选择@cus_id = max(id)+ 1TA
奥利
答案 0 :(得分:23)
使用Projection:
session.CreateCriteria(typeof(Customer))
.SetProjection( Projections.Max("Id") )
. UniqueResult();
答案 1 :(得分:15)
Max(id)+ 1是一种非常糟糕的生成ID的方法。如果这是您的目标,请找到另一种生成ID的方法。
编辑:回答LnDCobra:
这很糟糕,因为当你进行插入时很难确保你得到的max(id)仍然是max(id)。如果另一个进程插入一行,您的插入将具有相同的ID,并且您的插入将失败。 (或者,相反,如果您的插入首先发生,则其他进程的插入将失败。)
为了防止这种情况,你必须阻止任何其他插入/使你的get和后续插入原子,这通常意味着锁定表,这将损害性能。
如果您只锁定写入,则另一个进程获取max(id),这与您获得的max(id)相同。您执行插入并释放锁定,它会插入重复的ID并失败。或者它也试图锁定,在这种情况下它会等你。如果你也锁定读取,每个人都在等你。如果它也锁定了写入,那么它不会插入重复的id,但它会等待你的读取和写入。
(它破坏了封装:你应该让rdbms找出它的id,而不是连接到它的客户端程序。)
一般来说,这种策略要么:
*休息
*需要一堆“管道”代码才能使其正常工作
*显着降低性能
*或全部三个
它将比使用RDBMS的内置序列或生成的自动增量ID更慢,更不健壮,并且需要更难维护的代码。
答案 2 :(得分:0)
最佳方法是制作额外的Sequences表。 您可以在哪里维护序列目标和值。
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 will be = contractId