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

Expose Metadata generation #557

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions FakeXrmEasy.Shared/FakeXrmEasy.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
<Compile Include="$(MSBuildThisFileDirectory)FakeMessageExecutors\WinOpportunityRequestExecutor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)FiscalYearSettings.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IXrmFakedContext.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Metadata\CrmSvcUtilMetadataGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Metadata\DateTimeAttributeBehavior.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Metadata\MetadataGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Models\TypedConditionExpression.cs" />
Expand Down
247 changes: 247 additions & 0 deletions FakeXrmEasy.Shared/Metadata/CrmSvcUtilMetadataGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
using FakeXrmEasy.Extensions;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Metadata;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace FakeXrmEasy.Metadata
{
public static class CrmSvcUtilMetadataGenerator
{
public static void SetMetadata(EntityMetadata metadata, Type earlyBoundEntity, EntityLogicalNameAttribute entityLogicalNameAttribute)
{
metadata.LogicalName = entityLogicalNameAttribute.LogicalName;

FieldInfo entityTypeCode = earlyBoundEntity.GetField("EntityTypeCode", BindingFlags.Static | BindingFlags.Public);
if (entityTypeCode != null)
{
metadata.SetFieldValue("_objectTypeCode", entityTypeCode.GetValue(null));
}

List<AttributeMetadata> attributeMetadatas = new List<AttributeMetadata>();
List<ManyToManyRelationshipMetadata> manyToManyRelationshipMetadatas = new List<ManyToManyRelationshipMetadata>();
List<OneToManyRelationshipMetadata> oneToManyRelationshipMetadatas = new List<OneToManyRelationshipMetadata>();
List<OneToManyRelationshipMetadata> manyToOneRelationshipMetadatas = new List<OneToManyRelationshipMetadata>();

var idProperty = earlyBoundEntity.GetProperty("Id");
AttributeLogicalNameAttribute attributeLogicalNameAttribute;
if (idProperty != null && (attributeLogicalNameAttribute = GetCustomAttribute<AttributeLogicalNameAttribute>(idProperty)) != null)
{
metadata.SetFieldValue("_primaryIdAttribute", attributeLogicalNameAttribute.LogicalName);
}

var properties = earlyBoundEntity.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(x => x.Name != "Id" && Attribute.IsDefined(x, typeof(AttributeLogicalNameAttribute))
|| Attribute.IsDefined(x, typeof(RelationshipSchemaNameAttribute)));

foreach (var property in properties)
{
RelationshipSchemaNameAttribute relationshipSchemaNameAttribute = GetCustomAttribute<RelationshipSchemaNameAttribute>(property);
attributeLogicalNameAttribute = GetCustomAttribute<AttributeLogicalNameAttribute>(property);

if (relationshipSchemaNameAttribute == null)
{
#if !FAKE_XRM_EASY
if (property.PropertyType == typeof(byte[]))
{
metadata.SetFieldValue("_primaryImageAttribute", attributeLogicalNameAttribute.LogicalName);
}
#endif
AttributeMetadata attributeMetadata;
if (attributeLogicalNameAttribute.LogicalName == "statecode")
{
attributeMetadata = new StateAttributeMetadata();
}
else if (attributeLogicalNameAttribute.LogicalName == "statuscode")
{
attributeMetadata = new StatusAttributeMetadata();
}
else if (attributeLogicalNameAttribute.LogicalName == metadata.PrimaryIdAttribute)
{
attributeMetadata = new AttributeMetadata();
attributeMetadata.SetSealedPropertyValue("AttributeType", AttributeTypeCode.Uniqueidentifier);
}
else
{
attributeMetadata = CreateAttributeMetadata(property.PropertyType);
}

attributeMetadata.SetFieldValue("_entityLogicalName", entityLogicalNameAttribute.LogicalName);
attributeMetadata.SetFieldValue("_logicalName", attributeLogicalNameAttribute.LogicalName);

attributeMetadatas.Add(attributeMetadata);
}
else
{
if (property.PropertyType.Name == "IEnumerable`1")
{
PropertyInfo peerProperty = property.PropertyType.GetGenericArguments()[0].GetProperties()
.SingleOrDefault(x => x.PropertyType == earlyBoundEntity && GetCustomAttribute<RelationshipSchemaNameAttribute>(x)?.SchemaName == relationshipSchemaNameAttribute.SchemaName);

if (peerProperty == null || peerProperty.PropertyType.Name == "IEnumerable`1") // N:N relationship
{
ManyToManyRelationshipMetadata relationshipMetadata = new ManyToManyRelationshipMetadata();
relationshipMetadata.SchemaName = relationshipSchemaNameAttribute.SchemaName;

manyToManyRelationshipMetadatas.Add(relationshipMetadata);
}
else // 1:N relationship
{
AddOneToManyRelationshipMetadata(earlyBoundEntity, property, property.PropertyType.GetGenericArguments()[0], peerProperty, oneToManyRelationshipMetadatas);
}
}
else //N:1 Property
{
AddOneToManyRelationshipMetadata(property.PropertyType, property.PropertyType.GetProperties()
.SingleOrDefault(x => x.PropertyType.GetGenericArguments().SingleOrDefault() == earlyBoundEntity && GetCustomAttribute<RelationshipSchemaNameAttribute>(x)?.SchemaName == relationshipSchemaNameAttribute.SchemaName), earlyBoundEntity, property, manyToOneRelationshipMetadatas);
}
}
}
if (attributeMetadatas.Any())
{
metadata.SetSealedPropertyValue("Attributes", attributeMetadatas.ToArray());
}
if (manyToManyRelationshipMetadatas.Any())
{
metadata.SetSealedPropertyValue("ManyToManyRelationships", manyToManyRelationshipMetadatas.ToArray());
}
if (manyToOneRelationshipMetadatas.Any())
{
metadata.SetSealedPropertyValue("ManyToOneRelationships", manyToOneRelationshipMetadatas.ToArray());
}
if (oneToManyRelationshipMetadatas.Any())
{
metadata.SetSealedPropertyValue("OneToManyRelationships", oneToManyRelationshipMetadatas.ToArray());
}
}

private static T GetCustomAttribute<T>(this MemberInfo member) where T : Attribute
{
return (T)Attribute.GetCustomAttribute(member, typeof(T));
}

private static AttributeMetadata CreateAttributeMetadata(Type propertyType)
{
if (typeof(string) == propertyType)
{
return new StringAttributeMetadata();
}
else if (typeof(EntityReference).IsAssignableFrom(propertyType))
{
return new LookupAttributeMetadata();
}
#if FAKE_XRM_EASY || FAKE_XRM_EASY_2013 || FAKE_XRM_EASY_2015 || FAKE_XRM_EASY_2016 || FAKE_XRM_EASY_365
else if (typeof(Microsoft.Xrm.Client.CrmEntityReference).IsAssignableFrom(propertyType))
{
return new LookupAttributeMetadata();
}
#endif
else if (typeof(OptionSetValue).IsAssignableFrom(propertyType))
{
return new PicklistAttributeMetadata();
}
else if (typeof(Money).IsAssignableFrom(propertyType))
{
return new MoneyAttributeMetadata();
}
else if (propertyType.IsGenericType)
{
Type genericType = propertyType.GetGenericArguments().FirstOrDefault();
if (propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (typeof(int) == genericType)
{
return new IntegerAttributeMetadata();
}
else if (typeof(double) == genericType)
{
return new DoubleAttributeMetadata();
}
else if (typeof(bool) == genericType)
{
return new BooleanAttributeMetadata();
}
else if (typeof(decimal) == genericType)
{
return new DecimalAttributeMetadata();
}
else if (typeof(DateTime) == genericType)
{
return new DateTimeAttributeMetadata();
}
else if (typeof(Guid) == genericType)
{
return new LookupAttributeMetadata();
}
else if (typeof(long) == genericType)
{
return new BigIntAttributeMetadata();
}
else if (typeof(Enum).IsAssignableFrom(genericType))
{
return new StateAttributeMetadata();
}
else
{
throw new Exception($"Type {propertyType.Name}{genericType.Name} has not been mapped to an AttributeMetadata.");
}
}
else if (propertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
var partyList = new LookupAttributeMetadata();
partyList.SetSealedPropertyValue("AttributeType", AttributeTypeCode.PartyList);
return partyList;
}
else
{
throw new Exception($"Type {propertyType.Name}{genericType.Name} has not been mapped to an AttributeMetadata.");
}
}
else if (typeof(BooleanManagedProperty) == propertyType)
{
var booleanManaged = new BooleanAttributeMetadata();
booleanManaged.SetSealedPropertyValue("AttributeType", AttributeTypeCode.ManagedProperty);
return booleanManaged;
}
#if !FAKE_XRM_EASY && !FAKE_XRM_EASY_2013
else if (typeof(Guid) == propertyType)
{
return new UniqueIdentifierAttributeMetadata();
}
#endif
#if !FAKE_XRM_EASY
else if (typeof(byte[]) == propertyType)
{

return new ImageAttributeMetadata();
}
#endif
#if FAKE_XRM_EASY_9
else if (typeof(OptionSetValueCollection).IsAssignableFrom(propertyType))
{
return new MultiSelectPicklistAttributeMetadata();
}
#endif
else
{
throw new Exception($"Type {propertyType.Name} has not been mapped to an AttributeMetadata.");
}
}

private static void AddOneToManyRelationshipMetadata(Type referencingEntity, PropertyInfo referencingAttribute, Type referencedEntity, PropertyInfo referencedAttribute, List<OneToManyRelationshipMetadata> relationshipMetadatas)
{
if (referencingEntity == null || referencingAttribute == null || referencedEntity == null || referencedAttribute == null) return;
OneToManyRelationshipMetadata relationshipMetadata = new OneToManyRelationshipMetadata();
relationshipMetadata.SchemaName = GetCustomAttribute<RelationshipSchemaNameAttribute>(referencingAttribute).SchemaName;
relationshipMetadata.ReferencingEntity = GetCustomAttribute<EntityLogicalNameAttribute>(referencingEntity).LogicalName;
relationshipMetadata.ReferencingAttribute = GetCustomAttribute<AttributeLogicalNameAttribute>(referencingAttribute)?.LogicalName;
relationshipMetadata.ReferencedEntity = GetCustomAttribute<EntityLogicalNameAttribute>(referencedEntity).LogicalName;
relationshipMetadata.ReferencedAttribute = GetCustomAttribute<AttributeLogicalNameAttribute>(referencedAttribute).LogicalName;

relationshipMetadatas.Add(relationshipMetadata);
}
}
}
Loading