locked
Entity will not be added into added related state entries when there is referentialconstraint tag for the association in model RRS feed

  • Question

  • When there is referentialconstraint tag added for an association, the following code snippet could not get any entries when the related entity changed.

    var addedRelEntries = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Where(e => e.IsRelationship);
                if (addedRelEntries.Any())
                {
                    Console.WriteLine("---------------added relationship-----------------------");
                }
                foreach (var addRelEntry in addedRelEntries)
                {
                    var entityRelEndA = addRelEntry.EntitySet.Name;
                    EntityKey curRelEndA = addRelEntry.CurrentValues[0] as EntityKey;
                    EntityKey curRelEndB = addRelEntry.CurrentValues[1] as EntityKey;
                    Console.WriteLine(string.Format("Added EntitySet {0}, endA {1}, {2}, {3}, endB {4}, {5}, {6}", entityRelEndA,
                        curRelEndA.EntitySetName,
                        (curRelEndA.EntityKeyValues == null ? "" : curRelEndA.EntityKeyValues[0].Key),
                        (curRelEndA.EntityKeyValues == null ? "" : curRelEndA.EntityKeyValues[0].Value),
                        curRelEndB.EntitySetName,
                        (curRelEndB.EntityKeyValues == null ? "" : curRelEndB.EntityKeyValues[0].Key),
                        (curRelEndB.EntityKeyValues == null ? "" : curRelEndB.EntityKeyValues[0].Value)));
                }

    I checked the entity framework code and found,

    1. ReferentialConstraint will be handled here

    // System.Data.Entity.Core.SchemaObjectModel.Relationship
    protected override bool HandleElement(XmlReader reader)
    {
    if (base.HandleElement(reader))
    {
      return true;
    }
    if (base.CanHandleElement(reader, "End"))
    {
      this.HandleEndElement(reader);
      return true;
    }
    if (base.CanHandleElement(reader, "ReferentialConstraint")) <- constraint will be handled here
    {
      this.HandleConstraintElement(reader);
      return true;
    }
    return false;
    }

    2. In the HandleConstraintElement function, the isForeignKey will be set.

    // System.Data.Entity.Core.SchemaObjectModel.Relationship
    private void HandleConstraintElement(XmlReader reader)
    {
    ReferentialConstraint referentialConstraint = new ReferentialConstraint(this);
    referentialConstraint.Parse(reader);
    this.Constraints.Add(referentialConstraint);
    if (base.Schema.DataModel == SchemaDataModelOption.EntityDataModel && base.Schema.SchemaVersion >= 2.0)
    {
      this._isForeignKey = true;
    }
    }

    3. When checking relationship changes, the following function will be called,

    System.Data.Entity.Core.Objects.DataClasses.EntityReference<TEntity>.IncludeEntityKey

    4. Here is the snippet adding the change relationship to ObjectStateManager,

    if (!this.IsForeignKey)
       {
        if (entityEntry.State == EntityState.Added)
        {
         this.AddRelationshipToObjectStateManager(wrappedEntity, addRelationshipAsUnchanged, false);
        }
        else
        {
         this.AddRelationshipToObjectStateManager(wrappedEntity, addRelationshipAsUnchanged, doAttach);
        }
       }

    5. The IsForeignKey here comes from,

    // System.Data.Entity.Core.Objects.DataClasses.RelatedEnd
    internal bool IsForeignKey
    {
    get
    {
      return ((AssociationType)this._relationMetadata).IsForeignKey;
    }
    }
    ==================
                   
    // System.Data.Entity.Core.Metadata.Edm.AssociationType
    internal volatile int Index = -1;
    internal AssociationType(string name, string namespaceName, bool foreignKey, DataSpace dataSpace) : base(name, namespaceName, dataSpace)
    {
    this._referentialConstraints = new ReadOnlyMetadataCollection<ReferentialConstraint>(new MetadataCollection<ReferentialConstraint>());
    this._isForeignKey = foreignKey;  comes from parameter of constructor
    }
    ==================
    private static AssociationType ConvertToAssociationType(Relationship element, DbProviderManifest providerManifest, Converter.ConversionCache convertedItemCache, Dictionary<SchemaElement, GlobalItem> newGlobalItems)
    {
    AssociationType associationType = new AssociationType(element.Name, element.Namespace, element.IsForeignKey, Converter.GetDataSpace(providerManifest));  comes from Relationship
    newGlobalItems.Add(element, associationType);

    So, it is clear that as long as there is a referentialconstraint tag, the add entity will not be tracked for the association.

    My question is,

    1. Is this by design?

    2. If it is by design, why is it designed that way?

    3. If ObjectStateManager could not track this change, what is the alternative method.

    Monday, July 20, 2015 9:11 AM

All replies

  • Hello PeterZhuLang,

    >>When there is referentialconstraint tag added for an association, the following code snippet could not get any entries when the related entity changed.

    For question 1 and 2, from your provided code, they should be the source code, so I think the scenario you encounter should be by designed. For why the detail reason, since there is not a clear document about EF design, we are hard to tell.

    >>3. If ObjectStateManager could not track this change, what is the alternative method.

    You could check the RelationshipManager as below:

    using (DFDBEntities db = new DFDBEntities())
    
                {
    
    
                    OrderDetailSet od = new OrderDetailSet() { ODID = 1, ODName = "1" };
    
    
                    db.OrderDetailSets.Add(od);
    
    
                    Order order = db.Orders.FirstOrDefault();
    
    
                    order.OrderDetailSets.Add(od);
    
    
                    var objcontext = ((IObjectContextAdapter)db).ObjectContext;
    
    
                    var addedRelEntries = objcontext.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Select(s => s.RelationshipManager);
    
    
                    foreach (RelationshipManager rm in addedRelEntries)
    
                    {
    
                        foreach (var item in rm.GetAllRelatedEnds())
    
                        {
    
                               //get entity set information here you want
    
                        }
    
                    }
    

    In my scenario, I could get the new add relationship, using above code. Please try it and if not help, please share code about how you add a new entity with us so that we could check it.

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, July 21, 2015 4:35 AM
  • Thanks Fred for your answer.

    However, my questions that why only entityentry but no relationshipentry added to the set when there is referentialconstraint tag for the association.

    Besides, with your manager, if there is RelationshipEntry added to the set, we will get exception when execute the following code since RelationshipEntry does not RelationshipManager member.

    var addedRelEntries = objcontext.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Select(s => s.RelationshipManager);

    So, the code is actually not a common solution.

    Thursday, July 23, 2015 3:55 AM
  • Hello PeterZhuLang,

    For further helping your about this case, could you please provide a small demo which could reproduce this issue, we could test it and to see if we could help find a solution.

    Regards.

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Friday, July 24, 2015 1:54 AM
  • Fred,

    Please let me know how to send you my project.

    Best regards,

    Peter

    Friday, July 24, 2015 3:54 AM
  • HI PeterZhuLang,

    You could use the onedrive:https://onedrive.live.com/

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Friday, July 24, 2015 10:30 AM
  • You could download the test projects with the following link,

    https://onedrive.live.com/redir?resid=EED06AE727A2A4CC!142445&authkey=!AMbRm9UKE7XpIoI&ithint=folder%2c

    The EFCodeFirst1 is 1 to many relationship. Using your suggested code, there will be exception thrown out since relationshipentity is tracked and it does not have RelationshipManager member.

    The EFCodeFirst2 is 1 to 0..1 relationship. RelationshipEntity will not be tracked for this kind of relationship which will not cause the issue then.

    My question is just why different relationship will cause this difference. Based on my analysis now, for 1 to many relationship, there will be no referentialconstraint tag generated by EF. For 1 to 0..1 relationship, there will be. And with referentialconstraint tag added, RelationshipEntity will not be tracked. I want to know if this is a bug since even for different relationship type, the code behavior should be the same.

    Monday, July 27, 2015 2:34 AM
  • Hi Peter,

    I would download your project and to check if this is a not reported issue or a by designed feature. It may take some time and soon as I get any result, i will tell you.

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, July 27, 2015 1:36 PM
  • Hi Fred,

    Is there any update there?

    Best regards,

    Peter

    Friday, July 31, 2015 2:22 AM
  • Hello Peter,

    Sorry for replying later. I downloaded your projects and see the scenario you mention, I also made a source debug to see the code executed flow, while I am not able to find caused reason.

    For this case, I suggest you could post a feedback to the EF team to check if there is a reason for this:

    https://connect.microsoft.com/VisualStudio

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Friday, July 31, 2015 8:38 AM