我将 运行 设置为 IDENTITY_INSERT 或仅将一个对象保存到数据库中

I run into either IDENTITY_INSERT is set OFF or only one object will be saved into the database

我有这种方法,在进行一些评估后将数据保存到数据库中。在 foreach 迭代中,我检查在为对象赋值然后进一步插入数据库之前是否满足条件。当该方法运行时,它只会将 eligibleSupplier 的一个实例保存到数据库中或抛出 IDENTITY_INSERT 异常

public void EvaluationTenderBids(int tenderId)
    {
        var tender = _databaseContext.Tenders.Find(tenderId);
        var submittedTenders = _databaseContext.TenderBidSubmissions.Where(t => t.TenderId == tenderId).ToList();
        EligibleSupplier eligibleSupplier = new EligibleSupplier();
        tender.EligibleSuppliers = new List<EligibleSupplier>();


        var eligibleSuppliers = new List<EligibleSupplier>();

        decimal totProductQtAmt = 0;
        decimal totProductRecAmt = 0;
        decimal priceDifference = 0;
        
        
        
        foreach (var tenderBid in submittedTenders)
        {

            var tenderBidProducts = _databaseContext.TenderBidSubmissionProducts.Where(t => t.TenderBidSubmissionId == tenderBid.TenderBidSubmissionId).ToList();

            foreach(var product in tenderBidProducts)
            {
                var prod = _databaseContext.Products.Find(product.ProductId);
                product.RecommendedPrice = prod.ProductPrice;
                totProductQtAmt = product.QuotedPrice * product.Quantity;
                totProductRecAmt = product.RecommendedPrice * product.Quantity;

                priceDifference = totProductQtAmt - totProductRecAmt;
            }

            var company = _databaseContext.TenderBidSubmissions.Where(c => c.RegistrationNumber == tenderBid.RegistrationNumber).FirstOrDefault();

            decimal percentage = 0;

            if (priceDifference > 0)
            {
                percentage = ((priceDifference / tenderBid.TotalQuotation) * 100);
            }


            if (percentage > 27 && percentage <= 30)
            {
                eligibleSupplier.RegistrationNumber = company.RegistrationNumber;
                eligibleSupplier.CompanyName = company.CompanyName;
                eligibleSupplier.Tender = tender;
                eligibleSupplier.TenderId = tender.TenderId;
                eligibleSupplier.Score = 1;
                eligibleSupplier.InflationRate = percentage;
                eligibleSupplier.DateEvaluated = DateTime.Now;

                tender.EligibleSuppliers.Add(eligibleSupplier);
                _databaseContext.SaveChanges();

            }
            else if (percentage > 21 && percentage <= 24)
            {
                eligibleSupplier.RegistrationNumber = company.RegistrationNumber;
                eligibleSupplier.CompanyName = company.CompanyName;
                eligibleSupplier.Tender = tender;
                eligibleSupplier.TenderId = tender.TenderId;
                eligibleSupplier.Score = 2;
                eligibleSupplier.InflationRate = percentage;
                eligibleSupplier.DateEvaluated = DateTime.Now;

                tender.EligibleSuppliers.Add(eligibleSupplier);
                _databaseContext.SaveChanges();
            }
            else if (percentage > 18 && percentage < 21)
            {
                eligibleSupplier.RegistrationNumber = company.RegistrationNumber;
                eligibleSupplier.CompanyName = company.CompanyName;
                eligibleSupplier.Tender = tender;
                eligibleSupplier.TenderId = tender.TenderId;
                eligibleSupplier.Score = 3;
                eligibleSupplier.InflationRate = percentage;
                eligibleSupplier.DateEvaluated = DateTime.Now;

                tender.EligibleSuppliers.Add(eligibleSupplier);
                _databaseContext.SaveChanges();
            }
            else if (percentage > 15 && percentage <= 18)
            {
                eligibleSupplier.RegistrationNumber = company.RegistrationNumber;
                eligibleSupplier.CompanyName = company.CompanyName;
                eligibleSupplier.Tender = tender;
                eligibleSupplier.TenderId = tender.TenderId;
                eligibleSupplier.Score = 4;
                eligibleSupplier.InflationRate = percentage;
                eligibleSupplier.DateEvaluated = DateTime.Now;

                tender.EligibleSuppliers.Add(eligibleSupplier);
                _databaseContext.SaveChanges();
            }
            else if (percentage > 10 && percentage <= 15)
            {
                eligibleSupplier.RegistrationNumber = company.RegistrationNumber;
                eligibleSupplier.CompanyName = company.CompanyName;
                eligibleSupplier.Tender = tender;
                eligibleSupplier.TenderId = tender.TenderId;
                eligibleSupplier.Score = 5;
                eligibleSupplier.InflationRate = percentage;
                eligibleSupplier.DateEvaluated = DateTime.Now;


                tender.EligibleSuppliers.Add(eligibleSupplier);
                _databaseContext.SaveChanges();
            }
            else
                continue;
        
        }

    }

好的,您的代码有很多问题需要解决:

#1。对于实体,永远不要这样做:

var tender = _databaseContext.Tenders.Find(tenderId);
tender.EligibleSuppliers = new List<EligibleSupplier>();

当 EF 加载实体时,您希望它管理子集合。这意味着避免尝试使用新实例“重置”集合。加载现有投标时,您应该预先加载供应商集合,然后确定是否要 remove/replace 或编辑现有行,然后再添加新行。

Find 只有当你知道你只需要一个实体中的数据和相关实体的 none 时才真正有用,除非你想按需手动加载它们或依赖惰性加载。相反,您应该使用:

var tender = _databaseContext.Tenders
    .Include(x => x.EligibleSuppliers)
    .Single(x => x.TenderId == tenderId);

这将通过 ID 加载单个投标并预先加载当前记录的所有供应商。从那里您需要决定是否要更新任何现有 EligibleSuppliers 的值,或删除它们(即使用 tender.EligibleSuppliers.Clear())并重新添加新实体。

#2。 EF 尊重引用。不要对多个实体使用相同的引用。此处代码:

// Outside of a loop...
EligibleSupplier eligibleSupplier = new EligibleSupplier();

// Inside a loop...
eligibleSupplier.InflationRate = percentage;
eligibleSupplier.DateEvaluated = DateTime.Now;

tender.EligibleSuppliers.Add(eligibleSupplier);

这 99.9% 肯定是导致您眼前问题的原因。当您添加对供应商的引用,然后重新使用该引用时,您正在更新已添加到供应商的实例。

如果你想在一个循环中create/add一个新的供应商你需要声明一个新的实例,而不是重复使用同一个实例。

同样的问题会影响您的 priceDifference 计算。由于循环中的行,它只会尊重产品循环中 last 产品的值:

priceDifference = totProductQtAmt - totProductRecAmt;

这应该是这样的:

priceDifference += totProductQtAmt - totProductRecAmt;

如果您想知道所有订购产品的总价是否不同。 (即一些产品更多可能会抵消更少的产品)

#3。过度重复的条件代码。你的整个 if / else if / else if 都在做完全相同的事情,除了改变分数。

所有这些:

        if (percentage > 27 && percentage <= 30)
        {
            eligibleSupplier.RegistrationNumber = company.RegistrationNumber;
            eligibleSupplier.CompanyName = company.CompanyName;
            eligibleSupplier.Tender = tender;
            eligibleSupplier.TenderId = tender.TenderId;
            eligibleSupplier.Score = 1;
            eligibleSupplier.InflationRate = percentage;
            eligibleSupplier.DateEvaluated = DateTime.Now;

            tender.EligibleSuppliers.Add(eligibleSupplier);
            _databaseContext.SaveChanges();

        }
        else if (percentage > 21 && percentage <= 24)
        {
            eligibleSupplier.RegistrationNumber = company.RegistrationNumber;
            eligibleSupplier.CompanyName = company.CompanyName;
            eligibleSupplier.Tender = tender;
            eligibleSupplier.TenderId = tender.TenderId;
            eligibleSupplier.Score = 2;
            eligibleSupplier.InflationRate = percentage;
            eligibleSupplier.DateEvaluated = DateTime.Now;

            tender.EligibleSuppliers.Add(eligibleSupplier);
            _databaseContext.SaveChanges();
        }
        else if (percentage > 18 && percentage < 21)
        {
            eligibleSupplier.RegistrationNumber = company.RegistrationNumber;
            eligibleSupplier.CompanyName = company.CompanyName;
            eligibleSupplier.Tender = tender;
            eligibleSupplier.TenderId = tender.TenderId;
            eligibleSupplier.Score = 3;
            eligibleSupplier.InflationRate = percentage;
            eligibleSupplier.DateEvaluated = DateTime.Now;

            tender.EligibleSuppliers.Add(eligibleSupplier);
            _databaseContext.SaveChanges();
        }
        else if (percentage > 15 && percentage <= 18)
        {
            eligibleSupplier.RegistrationNumber = company.RegistrationNumber;
            eligibleSupplier.CompanyName = company.CompanyName;
            eligibleSupplier.Tender = tender;
            eligibleSupplier.TenderId = tender.TenderId;
            eligibleSupplier.Score = 4;
            eligibleSupplier.InflationRate = percentage;
            eligibleSupplier.DateEvaluated = DateTime.Now;

            tender.EligibleSuppliers.Add(eligibleSupplier);
            _databaseContext.SaveChanges();
        }
        else if (percentage > 10 && percentage <= 15)
        {
            eligibleSupplier.RegistrationNumber = company.RegistrationNumber;
            eligibleSupplier.CompanyName = company.CompanyName;
            eligibleSupplier.Tender = tender;
            eligibleSupplier.TenderId = tender.TenderId;
            eligibleSupplier.Score = 5;
            eligibleSupplier.InflationRate = percentage;
            eligibleSupplier.DateEvaluated = DateTime.Now;


            tender.EligibleSuppliers.Add(eligibleSupplier);
            _databaseContext.SaveChanges();
        }
        else
            continue;

可以用辅助方法代替:(参见:Is there a "between" function in C#?

public static bool Between(this int num, int lower, int upper, bool inclusive = false)
{
    return inclusive
        ? lower <= num && num <= upper
        : lower < num && num < upper;
}

然后:(假设您的逻辑有错字,因为第一盘是 27-30 而第二盘是 21-24,我怀疑您是要忽略 25-26...

int score = percentage.Between(24, 30) ? 1
    : percentage.Between(21, 24) ? 2
    : percentage.Between(18, 21) ? 3
    : percentage.Between(15, 18) ? 4
    : percentage.Between(10, 15) ? 5
    : 0;

if (score == 0)
    continue;

var eligibleSupplier = new EligibleSupplier
{
     RegistrationNumber = company.RegistrationNumber;
     CompanyName = company.CompanyName;
     Score = score;
     InflationRate = percentage;
     DateEvaluated = DateTime.Now;
};

tender.EligibleSuppliers.Add(eligibleSupplier);

将 Supplier 添加到 Tender 的集合时,您无需设置 EligibleSupplier.Tender 或 .TenderId,EF 会自动处理。这样做通常是无害的,只是没有必要。应始终避免在使用导航属性的地方设置 FK 字段(即 TenderId)。这可能会导致状态不一致,具体取决于当时是否加载导航 属性。