У меня проблема с EF 4.1 с использованием «Code First».Позвольте мне настроить ситуацию, прежде чем я начну публиковать любой код.У меня есть мой класс DBContext, называемый MemberSalesContext, в проекте библиотеки классов под названием Data.EF.У меня есть свои POCO в отдельном проекте библиотеки классов под названием Domain.Мой проект домена ничего не знает о Entity Framework, никаких ссылок, ничего.Мой проект Data.EF имеет ссылку на проект Domain, так что мой контекстный класс БД может соединить все в моих классах отображения, расположенных в Data.EF.Mapping.Я делаю все сопоставления в этом пространстве имен, используя класс EntityTypeConfiguration из EntityFramework.Все это довольно стандартные вещи.Поверх Entity Framework я использую шаблон репозитория и шаблон спецификации.
В моей таблице базы данных 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 убедитесь, что значения ключа уникальны. "
В этой ситуации изменения базы данных на второй итерации не были успешно завершены, ноИзменения в первой итерации были.Я убедился, что все объекты во внешнем и внутреннем циклах уникальны и привязаны к первичным ключам базы данных.
Есть ли что-то, чего мне здесь не хватает?Я готов дополнить мои примеры кода, если это окажется полезным.Я сделал все возможное, чтобы устранить эту проблему, за исключением изменения составного первичного ключа, установленного в таблице базы данных.
Может кто-нибудь помочь ???Большое спасибо заранее!Кстати, простите за длинный пост!