Skip to content
This repository has been archived by the owner on Jun 16, 2024. It is now read-only.

FindReflectedAttributeType Object reference not set to an instance of an object. #560

Open
ioanacro opened this issue May 27, 2021 · 20 comments

Comments

@ioanacro
Copy link

ioanacro commented May 27, 2021

Hi,
I have this test that is joining Account entity with my custom entity Project. When I add a condition on account I get
Object reference not set to an instance of an object. error in FakeXrmEasy.XrmFakedContext.FindReflectedAttributeType
when calling RetrieveMultiple method.

    [Test]
    public void TestStandardEntities()
    {
        this.context = new XrmFakedContext();
        var accountId = Guid.NewGuid();
        var AccountToBeFound = new Account { Id = accountId, Name = "TestAccount", AccountId = accountId };

        var ProjectToBeFound = new project
        {
            name = "TestProject",
            projectId = Guid.NewGuid(),
            projectcode = "someCode",
            accountid = AccountToBeFound.ToEntityReference()
        };

        this.context.Initialize(new List<Entity> { AccountToBeFound, ProjectToBeFound });

        this.service = this.context.GetOrganizationService();

        var xml = @"<fetch count='10' distinct='true' page='1'>
                            <entity name='project'>
                                <attribute name='projectid' />
                                   <filter type='or'>
                                         <condition entityname='account' attribute='name' operator='like' value='TestAccount%' />
                                   </filter>
                                <link-entity name='account' from='accountid' to='accountid'>
                                </link-entity>
                            </entity>
                         </fetch>";

        var response = this.service.RetrieveMultiple(new FetchExpression(xml));

        response.Entities.Count().Should().Be(1);
    }

This query is working fine on the real CRM database. What object is null in this case?

Using 1.57.0.0 version

Another thing I noticed is if I change my condition to use another account attribute like accountratingcode

then I get System.Exception : XrmFakedContext.FindReflectedAttributeType: Attribute accountratingcode not found for type ...Models.project

Looks like the library is looking in my custom entity for those attributes.

@jordimontana82
Copy link
Owner

Hi, latest version is 1.57.1, not sure if you tried that one and have the same issue there?

@jordimontana82
Copy link
Owner

Also, could you check if the new attribute was generated (assuming you're generating early bound entities with crmsvcutil?)

@ioanacro
Copy link
Author

ioanacro commented May 27, 2021

I've update to latest version and re-run EarlyBound generator tool from XRMToolbox and the problem still persists.

@jordimontana82
Copy link
Owner

Thanks @ioanacro ,

If you could please post the entire stack trace and the generated entities involved in this test, so the community might help? Otherwise it's going to be very difficult to reproduce.

Thanks!

@ioanacro
Copy link
Author

Hi @jordimontana82 ,

ProjectTest.txt
Competitor.txt
test.txt

I've attached the generated entities, I used new ones only for testing purposes.

My guess from the 2 errors above is that earlyBoundType in FindReflectedAttributeType is wfp_ProjectClass instead of Competitor and propertyInfo ends up being null since everything is substracted from attributeName="name".

This is the stack trace:
System.NullReferenceException : Object reference not set to an instance of an object.
at FakeXrmEasy.XrmFakedContext.FindReflectedAttributeType(Type earlyBoundType, String sEntityName, String attributeName)
at FakeXrmEasy.Extensions.FetchXml.XmlExtensionsForFetchXml.GetConditionExpressionValueCast(String value, XrmFakedContext ctx, String sEntityName, String sAttributeName, ConditionOperator op)
at FakeXrmEasy.Extensions.FetchXml.XmlExtensionsForFetchXml.ToConditionExpression(XElement elem, XrmFakedContext ctx)
at FakeXrmEasy.Extensions.FetchXml.XmlExtensionsForFetchXml.<>c__DisplayClass21_0.b__3(XElement el)
at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)
at FakeXrmEasy.Extensions.FetchXml.XmlExtensionsForFetchXml.ToFilterExpression(XElement elem, XrmFakedContext ctx)
at FakeXrmEasy.Extensions.FetchXml.XmlExtensionsForFetchXml.<>c__DisplayClass16_0.b__1(XElement el)
at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext() at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable1 source)
at FakeXrmEasy.Extensions.FetchXml.XmlExtensionsForFetchXml.ToCriteria(XDocument xlDoc, XrmFakedContext ctx)
at FakeXrmEasy.XrmFakedContext.TranslateFetchXmlDocumentToQueryExpression(XrmFakedContext context, XDocument xlDoc)
at FakeXrmEasy.FakeMessageExecutors.RetrieveMultipleRequestExecutor.Execute(OrganizationRequest req, XrmFakedContext ctx)
at FakeXrmEasy.XrmFakedContext.<>c__DisplayClass155_0.b__0(QueryBase req)
at FakeXrmEasy.XrmFakedContext.<>c__DisplayClass155_0.b__2(QueryBase req)
at FakeItEasy.Configuration.BuildableCallRule.Apply(IInterceptedFakeObjectCall fakeObjectCall) in C:\projects\fakeiteasy\src\FakeItEasy\Configuration\BuildableCallRule.cs:line 97
at FakeItEasy.Core.FakeManager.ApplyBestRule(IInterceptedFakeObjectCall fakeObjectCall) in C:\projects\fakeiteasy\src\FakeItEasy\Core\FakeManager.cs:line 261
at FakeItEasy.Core.FakeManager.FakeItEasy.Core.IFakeCallProcessor.Process(InterceptedFakeObjectCall fakeObjectCall) in C:\projects\fakeiteasy\src\FakeItEasy\Core\FakeManager.cs:line 173
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.ObjectProxy.RetrieveMultiple(QueryBase query)

@jordimontana82
Copy link
Owner

jordimontana82 commented May 29, 2021

In the FetchXml attached it seems you are trying to retrieve an attribute using the name of the entity instead of the attribute name:

 <attribute name='{wfp_ProjectTest.EntityLogicalName}' />

@ioanacro Could you remove this bit to see if that works?

@jordimontana82
Copy link
Owner

imagen

@ioanacro
Copy link
Author

ioanacro commented Jun 2, 2021

ou are trying to retrieve an attribute using the name of the entity instead of the attribute name:

Hey,
I still get 'Object reference not set to an instance of an object.' error with that line fixed or removed

@BetimBeja
Copy link
Contributor

[Test]
public void TestStandardEntities()
{
	this.context = new XrmFakedContext();
	var accountId = Guid.NewGuid();
	var competitor = new Competitor { Id = accountId, Name = "something to look for" };

	var project = new wfp_ProjectTest
	{
		wfp_Competitor = competitor.ToEntityReference(),
		wfp_ProjectTestId = Guid.NewGuid()
	};

	this.context.Initialize(new List<Entity> { competitor, project });

	this.service = this.context.GetOrganizationService();

	var xml = $@"<fetch top='50' >
				  <entity name='{wfp_ProjectTest.EntityLogicalName}' >
					<attribute name='{wfp_ProjectTest.EntityLogicalName}' />
					<filter>
					  <condition entityname='{Competitor.EntityLogicalName}' attribute='name' operator='like' value='%something%' />
					</filter>
					<link-entity name='competitor' from='competitorid' to='wfp_appointment' />
				  </entity>

				  <entity name='{wfp_ProjectTest.EntityLogicalName}' >
					<attribute name='{wfp_ProjectTest.Fields.wfp_ProjectTestId}' />
					<filter>
					  <condition entityname='{Competitor.EntityLogicalName}' attribute='{Competitor.Fields.Name}' operator='like' value='%something%' />
					</filter>
					<link-entity name='{Competitor.EntityLogicalName}' from='{Competitor.Fields.CompetitorId}' to='{wfp_ProjectTest.Fields.wfp_Competitor}' />
				  </entity>
				</fetch>";

	var response = this.service.RetrieveMultiple(new FetchExpression(xml));

	response.Entities.Count().Should().Be(1);
}

I don't think that specifying twice your entity node in the FetchXML is supported in FakeXrmEasy

@jordimontana82
Copy link
Owner

Good spot @BetimBeja That wasn't in the orignal bug at the top and I missed it @ioanacro .

Is that supported in the FetchXml schema even? I never seen a fetchXml with two entity nodes myself....

@ioanacro
Copy link
Author

ioanacro commented Jun 2, 2021

you are right! Bad copy&paste from the initial code:

I've modified the test to :
[Test]
public void TestStandardEntities()
{
this.context = new XrmFakedContext();
var accountId = Guid.NewGuid();
var competitor = new Competitor { Id = accountId, Name = "something to look for" };

        var project = new wfp_ProjectTest
        {
            wfp_Competitor = competitor.ToEntityReference(),
            wfp_ProjectTestId = Guid.NewGuid()
        };

        this.context.Initialize(new List<Entity> { competitor, project });

        this.service = this.context.GetOrganizationService();

        var xml = $@"<fetch top='50' >
                      <entity name='{wfp_ProjectTest.EntityLogicalName}' >
                        <attribute name='{wfp_ProjectTest.Fields.wfp_ProjectTestId}' />
                        <filter>
                          <condition entityname='{Competitor.EntityLogicalName}' attribute='{Competitor.Fields.Name}' operator='like' value='%something%' />
                        </filter>
                        <link-entity name='{Competitor.EntityLogicalName}' from='{Competitor.Fields.CompetitorId}' to='{wfp_ProjectTest.Fields.wfp_Competitor}' />
                      </entity>
                    </fetch>";

        var response = this.service.RetrieveMultiple(new FetchExpression(xml));

        response.Entities.Count().Should().Be(1);
    }

But still getting the error

@BetimBeja
Copy link
Contributor

BetimBeja commented Jun 3, 2021

@jordimontana82 I think I found the bug.

if (attributeInfo == null && attributeName.EndsWith("name"))
{
// Special case for referencing the name of a EntityReference
attributeName = attributeName.Substring(0, attributeName.Length - 4);
attributeInfo = GetEarlyBoundTypeAttribute(earlyBoundType, attributeName);
if (attributeInfo.PropertyType != typeof(EntityReference))
{
// Don't mess up if other attributes follow this naming pattern
attributeInfo = null;
}
}
here in this part, there is a check, if the string ends with name, which is valid because it is looking for the name property, but it doesn't find it in the wfp_ProjectTest entity and throws with a null reference in this line

@ioanacro
Copy link
Author

ioanacro commented Jun 3, 2021

@jordimontana82 I think I found the bug.

if (attributeInfo == null && attributeName.EndsWith("name"))
{
// Special case for referencing the name of a EntityReference
attributeName = attributeName.Substring(0, attributeName.Length - 4);
attributeInfo = GetEarlyBoundTypeAttribute(earlyBoundType, attributeName);
if (attributeInfo.PropertyType != typeof(EntityReference))
{
// Don't mess up if other attributes follow this naming pattern
attributeInfo = null;
}
}

here in this part, there is a check, if the string ends with name, which is valid because it is looking for the name property, but it doesn't find it in the wfp_ProjectTest entity and throws with a null reference in this line

Hi @BetimBeja,

But why it looks in wfp_projectTest for the attribute name? the condition is on Competitor:
<condition entityname='{Competitor.EntityLogicalName}' attribute='{Competitor.Fields.Name}'...>

@dkanaev
Copy link

dkanaev commented Sep 14, 2021

@jordimontana82 I faced the same problem, in my case, the problem is in this line
image

@BetimBeja
Copy link
Contributor

image
https://docs.microsoft.com/en-us/dotnet/api/system.type.basetype?view=net-5.0#remarks
I think you are creating Early Bound Entities with object returning properties...

@dkanaev
Copy link

dkanaev commented Sep 14, 2021

@BetimBeja yes, I created Early Bound Entities. But, it is not an object type.

[AttributeLogicalName("rr_unitcategories")]
public virtual IEnumerable<rr_UnitCategories> rr_UnitCategories { get; set; }

This property was autogenerated for multi-select optionset value

@BetimBeja
Copy link
Contributor

the next paragraph tells you that the same is valid for Interfaces too
image
What is the benefit of having the IEnumerable instead of a concrete class in this particular case?

@dkanaev
Copy link

dkanaev commented Sep 14, 2021

The point is I use EarlyBoundGenerator to generate this code and at the moment I did not find how to configure it for generating class instead of interface

@jordimontana82
Copy link
Owner

@ioanacro Which early bound generator did you use? Just to check if it's really the same issue...

@ioanacro
Copy link
Author

ioanacro commented Oct 7, 2021

Hey, I'm also using EarlyBoundGenerator

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants