Я пытаюсь сохранить несколько записей моей сущности сущности одного и того же времени в одном и том же типе, но получаю ошибку «Ошибка EF при сохранении: у зависимой роли есть несколько принципалов с разными значениями».
SubEntity выглядит так:
public class SubEntityMap : EntityTypeConfiguration<SubEntity>
{
public SubEntityMap()
{
//Primary key
HasKey(t => t.Id);
//Table & Column Mappings
ToTable("SubEntity", "dbo");
Property(t => t.Id).HasColumnName("Id").IsRequired();
Property(t => t.UpdateUser).HasColumnName("UpdateUser");
Property(t => t.CreatedDate).HasColumnName("CreatedDate").IsRequired();
Property(t => t.UpdateDate).HasColumnName("UpdDate").IsRequired();
Property(t => t.Del).HasColumnName("Del").IsRequired();
Property(t => t.MainEntityId).HasColumnName("MainEntityId").IsRequired();
Property(t => t.ValueRefId).HasColumnName("ValueRefId").IsRequired();
//Relationships
HasRequired(t => t.MainEntity)
.WithMany(t => t.SubEntities)
.HasForeignKey(d => d.MainEntityId);
HasRequired(t => t.Ref)
.WithMany()
.HasForeignKey(d => d.ValueRefId);
}
}
Отображение связанных сущностей:
public class MainEntityMap : EntityTypeConfiguration<MainEntity>
{
public MainEntityMap()
{
// Prim`enter code here`ary Key
this.HasKey(t => t.Id);
// Table & Column Mappings
this.ToTable("MainEntity");
this.Property(t => t.Id).HasColumnName("Id");
}
}
public class RefMap : EntityTypeConfiguration<Ref>
{
public RefMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Table & Column Mappings
this.ToTable("Ref", "dbo");
this.Property(t => t.Id).HasColumnName("Id")
.IsRequired();
this.Property(t => t.Code).HasColumnName("Code")
.IsRequired();
this.Property(t => t.Description).HasColumnName("Description")
.IsRequired();
}
}
Существует также тип SourceEntity, который похож на MainEntity и который также определяет отношение 1: N к таблице, которая является почти точной копией SubEntity.
(они определяют 2 разных шага нашего бизнес-процесса, поэтому нам пришлось продублировать основные объекты, соответствующие каждому шагу, а также их коллекции).
Приведенный ниже код копирует элементы subEntity из SourceEntity (шаг 1 бизнес-процесса) в MainEntity (шаг 2 бизнес-процесса)
public void CopyToSubEntity(SourceEntity sourceEntity, MainEntity mainEntity, string userName)
{
var sourceEntitySubEntities = GetSubEntities(sourceEntity.id);
var mainEntitySubs = new List<SubEntity>();
foreach (var sourceEntitySubEntity in sourceEntitySubEntities )
{
var subEntity = new subEntity
{
CreatedDate = DateTime.Now,
mainEntity = mainEntity,
ValueRef = sourceEntitySubEntity.ValueRef
};
_subEntityRepository.Add(subEntity);
}
}
Если я сделаю сохранение изменений для каждого из них, я смогу заставить его работать, но я хочу понять, что происходит. Исключение не дает никакой информации, кроме сообщения «Зависимая роль» имеет несколько принципалов с разными значениями.
Любое предложение?
EDIT:
Я отлаживал код EF, и корень проблемы в методе EF
private Dictionary<CompositeKey, PropagatorResult> ProcessKeys(
UpdateCompiler compiler, List<PropagatorResult> changes, Set<CompositeKey> keys)
{
var map = new Dictionary<CompositeKey, PropagatorResult>(
compiler.m_translator.KeyComparer);
foreach (var change in changes)
{
// Reassign change to row since we cannot modify iteration variable
var row = change;
var key = new CompositeKey(GetKeyConstants(row));
// Make sure we aren't inserting another row with the same key
PropagatorResult other;
if (map.TryGetValue(key, out other))
{
DiagnoseKeyCollision(compiler, change, key, other);
}
map.Add(key, row);
keys.Add(key);
}
return map;
}
Когда я в первый раз перебираю код, карта пуста и ключ добавляется к карте.
Во второй раз map.TryGetValue возвращает true.
Содержимое карты: {Сохранить: Цитата: {Id = Ключ: id21: ord0: 0, Field1 = ForeignKey: id8: ord1: 459, Field2 = ForeignKey: id10: ord2: 0 и т. Д.}}
содержимое ключа: {Key: id61: ord0: 0}
EF определяет свой собственный компаратор равенства:
private class CompositeKeyComparer : IEqualityComparer<CompositeKey>
{
private readonly KeyManager _manager;
internal CompositeKeyComparer(KeyManager manager)
{
DebugCheck.NotNull(manager);
_manager = manager;
}
// determines equality by comparing each key component
public bool Equals(CompositeKey left, CompositeKey right)
{
// Short circuit the comparison if we know the other reference is equivalent
if (ReferenceEquals(left, right))
{
return true;
}
// If either side is null, return false order (both can't be null because of
// the previous check)
if (null == left
|| null == right)
{
return false;
}
Debug.Assert(
null != left.KeyComponents && null != right.KeyComponents,
"(Update/JoinPropagator) CompositeKey must be initialized");
if (left.KeyComponents.Length
!= right.KeyComponents.Length)
{
return false;
}
for (var i = 0; i < left.KeyComponents.Length; i++)
{
var leftValue = left.KeyComponents[i];
var rightValue = right.KeyComponents[i];
// if both side are identifiers, check if they're the same or one is constrained by the
// other (if there is a dependent-principal relationship, they get fixed up to the same
// value)
if (leftValue.Identifier
!= PropagatorResult.NullIdentifier)
{
if (rightValue.Identifier == PropagatorResult.NullIdentifier
||
_manager.GetCliqueIdentifier(leftValue.Identifier) != _manager.GetCliqueIdentifier(rightValue.Identifier))
{
return false;
}
}
else
{
if (rightValue.Identifier != PropagatorResult.NullIdentifier
||
!ByValueEqualityComparer.Default.Equals(leftValue.GetSimpleValue(), rightValue.GetSimpleValue()))
{
return false;
}
}
}
return true;
}
Как имеет значение тот факт, что EF говорит, что они - одна и та же запись?