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

System.InvalidOperationException: The requested key attributes do not exist for the entity #470

Open
romangobrey opened this issue Jan 3, 2020 · 6 comments

Comments

@romangobrey
Copy link

Hi,

Another "attribute related" issue I guess :)
Found nothing while googling...

I'm using early-bound types and getting the "System.InvalidOperationException: The requested key attributes do not exist for the entity contact" error.
An exception is thrown at FakeXrmEasy.XrmFakedContext.GetRecordUniqueId(EntityReference record, Boolean validate) call.

I'm using:
Crm Sdk Assemblies: v8.2.0.2
FakeXrmEasy.365: v1.55.0
FakeItEasy: v3.2.0

My library is targeting .Net v.4.5.2

The code is below
Thanks!

using System;
using System.Reflection;
using FakeXrmEasy;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using NUnit.Framework;

[assembly: ProxyTypesAssembly]

namespace UnitTestProject1
{
    [EntityLogicalName("contact")]
    public class ContactEntity : Entity
    {
        public ContactEntity() : base("contact")
        {
        }

        [AttributeLogicalName("firstname")]
        public string FirstName
        {
            get => GetAttributeValue<string>("firstname");
            set => SetAttributeValue("firstname", value);
        }
    }

    [TestFixture]
    public class UnitTest1
    {
        [Test]
        public void TestMethod1()
        {
            var context = new XrmFakedContext {ProxyTypesAssembly = Assembly.GetAssembly(typeof(ContactEntity))};
            context.Initialize(new ContactEntity {Id = Guid.NewGuid(), FirstName = "John"});

            var service = context.GetOrganizationService();

            var request = new RetrieveRequest
            {
                Target = new EntityReference("contact", "firstname", "John"),
                ColumnSet = new ColumnSet(true)
            };

            service.Execute(request);
        }
    }
}

@BetimBeja
Copy link
Contributor

Hello Roman,
you are trying to do an alternate key retrieval, and the only way to test that is to specify the alternate key in the entity metadata. Here you can find some examples with the upsert request that might help with setting up the context.

Best regards,
Betim.

@romangobrey
Copy link
Author

romangobrey commented Jan 3, 2020

That worked. Thank you!

Another related finding:
If I add to an entity a bool property or object property like this:

[AttributeLogicalName("hasPhone")]
public bool HasPhone
{
   get => GetAttributeValue<bool>("hasPhone");
   set => SetAttributeValue("hasPhone", value);
}

[AttributeLogicalName("object1")]
public object Object1
{
   get => GetAttributeValue<object>("object1");
   set => SetAttributeValue("object1", value);
}

And init the metadata like this:

var assembly = Assembly.GetExecutingAssembly();
var context = new XrmFakedContext { ProxyTypesAssembly = assembly };
context.InitializeMetadata(assembly);

I am getting errors at context.InitializeMetadata(assembly) like:

  • System.Exception: 'Type Boolean has not been mapped to an AttributeMetadata.'
  • System.Exception: 'Type Object has not been mapped to an AttributeMetadata.'

If I remove Object property and use nullable bool property it works...
Is it a bug or metadata has to follow some rules?

@BetimBeja
Copy link
Contributor

Hello,
fake-xrm-easy tries to generate the metadata by exploiting conventions in the generated code from crmsvcutil a.k.a. Early-Bound entities. If you write your code manually it would be ok for small tests but usually it is not a feasible option for all your codebase.
Best regards,
Betim.

@romangobrey
Copy link
Author

@BetimBeja,

Thank you for explanation. Makes sense!

One more question.
Real Context
Making the RetrieveRequest we can specify the value for key attribute that does not exist.
In this case real XrmContext throws "A record with the specified key values does not exist in entity" message with exception type: FaultException with OrganizationServiceFault inside

Fake Context
However, when creating a fake context, with the value for key attribute that does not exist, it throws "The requested key attributes do not exist for the entity systemuser" message with exception type: System.InvalidOperationException

Shouldn't fake context also throw the same type of exception FaultException?

Final Finding
I found out the an exception is thrown in GetRecordUniqueId method.
Below is the code.
An exception is fired inside the last "IF" statement.
The question is about code, marked with "//??" comment below.
The faultException object has been created there, but it's not thrown.

public Guid GetRecordUniqueId(EntityReference record, bool validate = true)
{
	if (string.IsNullOrWhiteSpace(record.LogicalName))
		throw new InvalidOperationException("The entity logical name must not be null or empty.");
	if (!this.Data.ContainsKey(record.LogicalName) && !this.EntityMetadata.ContainsKey(record.LogicalName))
	{
		if (this.ProxyTypesAssembly == (Assembly)null)
			throw new InvalidOperationException("The entity logical name " + record.LogicalName + " is not valid.");
		if (!((IEnumerable<Type>)this.ProxyTypesAssembly.GetTypes()).Any<Type>((Func<Type, bool>)(type => this.FindReflectedType(record.LogicalName) != (Type)null)))
			throw new InvalidOperationException("The entity logical name " + record.LogicalName + " is not valid.");
	}

	if (record.Id == Guid.Empty && record.HasKeyAttributes())
	{
		if (this.EntityMetadata.ContainsKey(record.LogicalName))
		{
			foreach (EntityKeyMetadata key in this.EntityMetadata[record.LogicalName].Keys)
			{
				if (record.KeyAttributes.Keys.Count == key.KeyAttributes.Length && ((IEnumerable<string>)key.KeyAttributes).All<string>((Func<string, bool>)(x => record.KeyAttributes.Keys.Contains(x))))
				{
					if (this.Data.ContainsKey(record.LogicalName))
					{
						Entity entity = this.Data[record.LogicalName].Values.SingleOrDefault<Entity>((Func<Entity, bool>)(x => record.KeyAttributes.All<KeyValuePair<string, object>>((Func<KeyValuePair<string, object>, bool>)(k => x.Attributes.ContainsKey(k.Key) && x.Attributes[k.Key] != null && x.Attributes[k.Key].Equals(k.Value)))));
						if (entity != null)
							return entity.Id;
					}

					if (validate)
					{
						//??
						FaultException <OrganizationServiceFault> faultException = new FaultException<OrganizationServiceFault>(new OrganizationServiceFault(), record.LogicalName + " with the specified Alternate Keys Does Not Exist");
					}
				}
			}
		}

		if (validate)
			throw new InvalidOperationException("The requested key attributes do not exist for the entity " + record.LogicalName);
	}

	return record.Id;
}

@SvenRahnSIT
Copy link

SvenRahnSIT commented Nov 28, 2023

We are also affected by this issue. I guess it can be fixed by just adding a throw here:

new FaultException<OrganizationServiceFault>(new OrganizationServiceFault(), $"{record.LogicalName} with the specified Alternate Keys Does Not Exist");

@jordimontana82
Copy link
Owner

Dear @SvenRahnSIT this issue tracker is for the deprecated v1.x version. In case you're using version 2 or later we have another issue tracker here: https://github.com/DynamicsValue/fake-xrm-easy.

If you're a commercial customer please drop us an email at support@dynamicsvalue.com

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

No branches or pull requests

4 participants