【发布时间】:2011-06-17 03:00:13
【问题描述】:
我在使用“代码优先”的 EF 4.1 时遇到问题。让我在开始发布任何代码之前设置我的情况。我在一个名为 Data.EF 的类库项目中有一个名为 MemberSalesContext 的 DBContext 类。我在一个名为 Domain 的单独类库项目中有我的 POCO。 My Domain 项目对实体框架一无所知,没有引用,什么都没有。我的 Data.EF 项目具有对 Domain 项目的引用,因此我的 DB 上下文类可以连接位于 Data.EF.Mapping 中的映射类中的所有内容。我正在使用 EntityFramework 中的 EntityTypeConfiguration 类在此命名空间中进行所有映射。所有这些都是非常标准的东西。在实体框架之上,我使用了存储库模式和规范模式。
我的 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 之前确保键值是唯一的。"
在这种情况下,第二次迭代中的数据库更改未成功提交,但第一次迭代中的更改已成功提交。我已确保外循环和内循环中的对象都是唯一的,并遵循数据库主键。
这里有什么我遗漏的吗?如果证明有帮助,我愿意增加我的代码示例。除了修改数据库表上的复合主键集之外,我已尽我所能解决此问题。
谁能帮忙???非常感谢提前!顺便说一句,对不起,很长的帖子!
【问题讨论】:
-
为什么要明确处理交易?
-
我不确定...但是 EF 可能会因为您声明 XREF_ID 属性具有数据库生成的“身份”选项而感到困惑。也许 EF 假设这是这种情况下的 PK?你玩过那个映射吗?
标签: repository-pattern entity-framework-4.1 unit-of-work