我将 运行 设置为 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)。这可能会导致状态不一致,具体取决于当时是否加载导航 属性。
我有这种方法,在进行一些评估后将数据保存到数据库中。在 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)。这可能会导致状态不一致,具体取决于当时是否加载导航 属性。