我遇到了使用「代碼優先」的EF 4.1問題。讓我在開始發佈任何代碼之前設置自己的狀況。我在名爲Data.EF的類庫項目中有我的DBContext類,名爲MemberSalesContext。我在一個名爲Domain的獨立類庫項目中有我的POCO。 My Domain項目對Entity Framework一無所知,沒有任何引用,沒有任何內容。我的Data.EF項目有一個對Domain項目的引用,以便我的數據庫上下文類可以連接位於Data.EF.Mapping中的映射類中的所有內容。我正在使用EntityFramework的EntityTypeConfiguration類來完成這個命名空間中的所有映射。所有這些都是非常標準的東西。在Entity Framework之上,我使用了Repository模式和Specification模式。EF代碼CommitTransaction上的第一個問題 - 使用存儲庫模式
我的SQL Server數據庫表有一個複合主鍵定義。屬於密鑰的三列是Batch_ID,RecDate和Supplier_Date。該表作爲標識列(數據庫生成的值=> +1)稱爲XREF_ID,它不是PK的一部分。
我的映射類,位於Data.EF.Mapping如下所示:
public class CrossReferenceMapping : EntityTypeConfiguration<CrossReference>
{
public CrossReferenceMapping()
{
HasKey(cpk => cpk.Batch_ID);
HasKey(cpk => cpk.RecDate);
HasKey(cpk => cpk.Supplier_Date);
Property(p => p.XREF_ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
ToTable("wPRSBatchXREF");
}
}
我MemberSalesContext類(從繼承的DbContext)如下所示:
public class MemberSalesContext : DbContext, IDbContext
{
//...more DbSets here...
public DbSet<CrossReference> CrossReferences { get; set; }
//...more DbSets here...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
//...more modelBuilder here...
modelBuilder.Configurations.Add<CrossReference>(new CrossReferenceMapping());
//...more modelBuilder here...
}
}
我有一個使用我的存儲庫返回迭代的對象列表的類中的私有方法。我所指的列表是下例中最外面的foreach循環。
private void CloseAllReports()
{
//* get list of completed reports and close each one (populate batches)
foreach (SalesReport salesReport in GetCompletedSalesReports())
{
try
{
//* aggregate sales and revenue by each distinct supplier_date in this report
var aggregates = BatchSalesRevenue(salesReport);
//* ensure that the entire SalesReport breaks out into Batches; success or failure per SalesReport
_repository.UnitOfWork.BeginTransaction();
//* each salesReport here will result in one-to-many batches
foreach (AggregateBySupplierDate aggregate in aggregates)
{
//* get the batch range (type) from the repository
BatchType batchType = _repository.Single<BatchType>(new BatchTypeSpecification(salesReport.Batch_Type));
//* get xref from repository, *if available*
//* some will have already populated the XREF
CrossReference crossReference = _repository.Single<CrossReference>(new CrossReferenceSpecification(salesReport.Batch_ID, salesReport.RecDate, aggregate.SupplierDate));
//* create a new batch
PRSBatch batch = new PRSBatch(salesReport,
aggregate.SupplierDate,
BatchTypeCode(batchType.Description),
BatchControlNumber(batchType.Description, salesReport.RecDate, BatchTypeCode(batchType.Description)),
salesReport.Zero_Sales_Flag == false ? aggregate.SalesAmount : 1,
salesReport.Zero_Sales_Flag == false ? aggregate.RevenueAmount : 0);
//* populate CrossReference property; this will either be a crossReference object, or null
batch.CrossReference = crossReference;
//* close the batch
//* see PRSBatch partial class for business rule implementations
batch.Close();
//* check XREF to see if it needs to be added to the repository
if (crossReference == null)
{
//*add the Xref to the repository
_repository.Add<CrossReference>(batch.CrossReference);
}
//* add batch to the repository
_repository.Add<PRSBatch>(batch);
}
_repository.UnitOfWork.CommitTransaction();
}
catch (Exception ex)
{
//* log the error
_logger.Log(User, ex.Message.ToString().Trim(), ex.Source.ToString().Trim(), ex.StackTrace.ToString().Trim());
//* move on to the next completed salesReport
}
}
}
在外循環的第一次迭代中一切順利。在外循環的第二次迭代中,代碼在_repository.UnitOfWork.CommitTransaction()處失敗。返回的錯誤消息如下:
「對數據庫的更改已成功提交,但更新對象上下文時發生錯誤。ObjectContext可能處於不一致狀態。內部異常消息:AcceptChanges無法繼續,因爲對象的鍵值與ObjectStateManager中的另一個對象衝突。在調用AcceptChanges之前,確保鍵值是唯一的。
在這種情況下,第二次迭代的數據庫更改未成功提交,但第一次迭代中的更改爲。我確保外部和內部循環中的對象都是唯一的,並遵守數據庫主鍵。
有什麼,我在這裏失蹤?如果證明有幫助,我願意增加我的代碼示例。我已經盡我所能解決了這個問題,減去修改數據庫表上的組合主鍵集。
任何人都可以幫助嗎?非常感謝提前!順便說一句,很抱歉,很長的文章!
你爲什麼明確處理交易? – Eranga 2011-06-17 04:08:25
我不確定...但EF可能會因爲您聲明XREF_ID屬性具有數據庫生成選項「Identity」而感到困惑。也許EF認爲這是這種情況下的PK?你玩過那個映射嗎? – 2011-06-18 22:10:41