7

Bir denetim günlüğü uygulamak için DbContext'im üzerinde SaveChanges'i geçersiz kılıyorum. Çoktan çoğa ilişkilerle veya bağımsız ilişkilendirmelerle çalışmak, EF bu tür ilişkilerde yapılacak herhangi bir değişiklik için ObjectStateEntries oluşturduğundan göreceli olarak kolaydır.Entity Framework: FK derneklerindeki değişiklikleri izleme

Yabancı anahtar ilişkilendirmelerini kullanıyorum ve varlıklar arasındaki ilişkiyi aldığınız tüm değişiklikler, örneğin "Başlık" öğesinin "PublisherID" özelliğinin değiştiğini belirten bir ObjectStateEnty öğesidir. Bir insana, bu açıkça Başlık varlığındaki yabancı bir anahtardır, fakat bunu çalışma zamanında nasıl belirleyebilirim? Yabancı anahtarın temsil ettiği varlık için bir EntityKey'e izin vermek için bu değişikliği "Yayıncı Kimliği" özelliğine çevirmenin bir yolu var mı? Ben

public TitleConfiguration() 
{ 
    HasOptional<Publisher>(t => t.Publisher).WithMany(
      p => p.Titles).HasForeignKey(t => t.PublisherID); 
} 

yapıyorum Ne:

public sealed class Publisher 
{ 
    public Guid ID { get; set; } 
    public string Name { get; set; } 
    public ICollection<Title> Titles { get; set; } 
} 

public class Title 
{ 
    public Guid ID { get; set; } 
    public string Name { get; set; } 
    public Guid? PublisherID { get; set; } 
    public Publisher Publisher { get; set; } 
} 

da ilişki ve yabancı anahtarını tanımlayan EF EntityConfiguration kodu vardır:

Ben şuna benzer kuruluşlar uğraşıyorum varsayalım şimdi biraz fazla karmaşık görünüyor. Hedefime ulaşmak için daha zarif bir yol olduğunu umuyorum. ObjectStateEntry tarafından değiştirilen her özellik için, geçerli varlık için tüm ReferentialConstraints bakın ve bunlardan herhangi birinin bir yabancı anahtar olarak kullanıp kullanmadığına bakın. Aşağıda SaveChanges (çağrılır kodu):

private void HandleProperties(ObjectStateEntry entry, 
     ObjectContext ctx) 
{ 
    string[] changedProperties = entry.GetModifiedProperties().ToArray(); 
    foreach (string propertyName in changedProperties) 
    { 
     HandleForeignKey(entry, ctx, propertyName); 
    } 
} 

private void HandleForeignKey(ObjectStateEntry entry, 
     ObjectContext ctx, string propertyName) 
{ 
    IEnumerable<IRelatedEnd> relatedEnds = 
      entry.RelationshipManager.GetAllRelatedEnds(); 

    foreach (IRelatedEnd end in relatedEnds) 
    { 
     // find foreign key relationships 
     AssociationType elementType = end.RelationshipSet.ElementType as 
       AssociationType; 
     if (elementType == null || !elementType.IsForeignKey) continue; 

     foreach (ReferentialConstraint constraint in 
       elementType.ReferentialConstraints) 
     { 
      // Multiplicity many means we are looking at a foreign key in a 
      // dependent entity 
      // I assume that ToRole will point to a dependent entity, don't 
      // know if it can be FromRole 
      Debug.Assert(constraint.ToRole.RelationshipMultiplicity == 
        RelationshipMultiplicity.Many); 
      // If not 1 then it is a composite key I guess. 
      // Becomes a lot more difficult to handle. 
      Debug.Assert(constraint.ToProperties.Count == 1); 
      EdmProperty prop = constraint.ToProperties[0]; 

      // entity types of current entity and foreign key entity 
      // must be the same 
      if (prop.DeclaringType == entry.EntitySet.ElementType 
        && propertyName == prop.Name) 
      { 
       EntityReference principalEntity = end as EntityReference; 
       if (principalEntity == null) continue; 

       EntityKey newEntity = principalEntity.EntityKey; 
       // if there is more than one, the foreign key is composite 
       Debug.Assert(newEntity.EntityKeyValues.Length == 1); 

       // create an EntityKey for the old foreign key value 
       EntityKey oldEntity = null; 

       if (entry.OriginalValues[prop.Name] is DBNull) 
       { 
        oldEntity = new EntityKey(); 
        oldEntity.EntityKeyValues = new[] { 
         new EntityKeyMember("ID", "NULL") 
        }; 
        oldEntity.EntitySetName = newEntity.EntitySetName; 
       } 
       else 
       { 
        Guid oldGuid = Guid.Parse(
          entry.OriginalValues[prop.Name].ToString()); 
        oldEntity = ctx.CreateEntityKey(newEntity.EntitySetName, 
          new Publisher() 
          { 
           ID = oldGuid 
          }); 
       } 

       Debug.WriteLine(
         "Foreign key {0} changed from [{1}: {2}] to [{3}: {4}]", 
         prop.Name, 
         oldEntity.EntitySetName, oldEntity.EntityKeyValues[0], 
         newEntity.EntitySetName, newEntity.EntityKeyValues[0]); 
      } 
     } 
    } 
} 

Bu elde etmek çalışıyorum daha iyi ne göstermek için yardımcı olur. Herhangi bir giriş açığız.

Teşekkürler!/

hepten bu sorunu önlemek için bağımsız dernek kullanarak sonuna yaptı: my kod bu soruna doğru çözüm gibi

+0

Denetimde neyin yanlış olduğu sadece bir değişiklik mi? Doğrudan veritabanında denetleme yaparsanız, kimliğinizi de değiştirmiş olursunuz. Btw. beğenmezseniz neden bağımsız dernekler yerine FK dernekleri kullanıyorsunuz? –

+0

Son kullanıcılara PublisherID'den b087929b-3221-4c43-916b-ad49066969c8'den 6372b8b6-1848-4f7a-ada0-d778a5682d67 'ye değiştiğinden daha açıklayıcı bir şey sağlamaya çalışıyorum. Muhtemelen varlığa işaret eden bir köprü. Bu nedenle ya denetim günlüğü için veri toplama noktasında veya denetim günlüğünü görüntülerken, bir mülkün yabancı bir anahtar olup olmadığını ve işaret ettiği varlığın ne tür olduğunu anlamaya ihtiyacım olacaktır. – LeffeBrune

+0

Bağımsız dernekler hakkındaki makalenizi okudum ve bu rotayı seçmeyi tercih edersem daha sonra bazı sorunlarla karşılaşabileceğimi hissettim. Bunun üzerine, eğer POCO varlıklarını uygun bir yabancı anahtar değerine sahip hale getirmeye karar verirsem, işe yarayabilir. Bağımsız dernekler ile, bu verinin faydalı olabilmesi için bir çeşit varlık grafiğini serileştirmem gerekecek. – LeffeBrune

cevap