保证不插入重复记录?

Guarantee a duplicate record is not inserted?

我有一些插入记录的代码,我想先删除所有具有匹配元组的现有记录。从许多可执行文件中快速调用此代码:

public void AddMemberEligibility(long memberId, string internalContractKey, int planSponsorId, int vendorId, string vendorContractKey) {
    using (IDocumentSession session = Global.DocumentStore.OpenSession()) {
        var existingMember = session.Query<MemberEligibility>().FirstOrDefault(x => x.VendorId == vendorId 
                               && x.MemberId == memberId && x.PlanSponsorId == planSponsorId);
        if (existingMember != null) {
            session.Delete<MemberEligibility>(existingMember);
            session.SaveChanges();
        }

        Eligibility elig = new Eligibility() {
            InternalContractKey = internalContractKey,
            MemberId = memberId,
            PlanSponsorId = planSponsorId,
            VendorId = vendorId
        };

        session.Store(elig);
        session.SaveChanges();
    }
}

这似乎不足以防止重复。有什么建议吗?

哈希集合可以很好地解决这个问题。

它在输入时调用 hashCode() 并包含使集合保持一定组织性的函数,然后使用 equals() 来测试重叠的哈希码。这种组合使它的 put 和 contains 函数通常为 0(1);尽管如果说所有哈希码都相同,那么它会将包含增加到 0(logn)。

很可能并发哈希集合更可取。如果你在 java(看起来像),你可以使用 CurrentHashSet

在听取了 Oren Eini 关于 Raven Google 组的建议后,我最终做的是使用 Unique Constraints Bundle

我的 DTO 现在看起来像这样:

using Raven.Client.UniqueConstraints;

public class MemberEligibility {
    [UniqueConstraint]
    public string EligibilityKey { get { return $"{MemberId}_{VendorId}_{PlanSponsorId}_{VendorContractKey}"; } }
    public long MemberId { get; set; }
    public int VendorId { get; set; }
    public int PlanSponsorId { get; set; }
    public string VendorContractKey { get; set; }
    // other fields
}

我的 add/update 看起来像这样:

public void AddMemberEligibility(long memberId, int planSponsorId, int vendorId, string vendorContractKey, ...) {
    using (IDocumentSession session = Global.DocumentStore.OpenSession()) {
        MemberEligibility elig = new MemberEligibility() {
            MemberId = memberId,
            PlanSponsorId = planSponsorId,
            VendorId = vendorId,
            VendorContractKey = vendorContractKey,
            //other stuff
        };

        var existing = session.LoadByUniqueConstraint<MemberEligibility>(x => x.EligibilityKey, elig.EligibilityKey);
        if (existing != null) {
            // set some fields
        } else {
            session.Store(elig);
        }
        session.SaveChanges();
    }
}

在这一点上,我不能 100% 确定这是我将投入生产的解决方案,但它确实有效。请记住,如果商店中已经存在具有相同 [UniqueConstraint] 属性 的文档,session.SaveChanges() 将抛出异常。此外,我开始将此 属性 键入为 Tuple<...>,但 Raven 的序列化程序无法弄清楚如何使用它,所以我暂时选择了 string