作者:seaknkoo_776 | 来源:互联网 | 2023-02-03 17:24
所述XRM SDK定义一个ToEntity
方法.我一直用它来从CRM中获取早期绑定的实体.今天我正在审查一些代码并看到实体刚刚被投射:
var cOntact= service.Retrieve("contact", id, new ColumnSet()) as Contact;
我甚至都不知道这是可能的.是否甚至需要ToEntity电话?
1> James Wood..:
除此之外,这不是一个特定的演员,它是一个转换,并且转换的行为与直接演员的行为略有不同.
如
您可以使用as运算符在兼容的引用类型或可空类型之间执行某些类型的转换... as运算符就像一个转换操作.但是,如果无法进行转换,则返回null而不是引发异常.
我假设你Contact
是CrmSvcUtil例如,创建一个类public partial class Contact : Microsoft.Xrm.Sdk.Entity
,并且service.Retrieve
是IOrganizationService.Retrieve具有的返回类型Entity
.
Contact
是基类的派生类Entity
.您不能将基类强制转换为更具体的派生类(请参阅是否可以使用C#中的显式类型转换将基类对象分配给派生类引用?).如果你试图从一个做投Entity
来Contact
,你会得到一个异常,并转换将返回一个空的对象.
包含来自CrmSvcUtil的GeneratedCode的示例,但没有与CRM的实际连接.
var entity = new Entity();
Console.WriteLine($"Type of local entity: {entity.GetType()}");
Console.WriteLine($"Local entity as Contact is null? {entity as COntact== null}");
输出:
Type of local entity: Microsoft.Xrm.Sdk.Entity
Local entity as Contact is null? True
所以给定Retrieve
返回一个Entity
,不能转换为Contact
,你的代码行(var cOntact= service.Retrieve("contact", id, new ColumnSet()) as Contact;
)甚至如何工作?
嗯,这很神奇.显然,如果在应用程序中包含CrmSvcUtil的GeneratedCode,该Retrieve
函数将返回特定的派生类而不是泛型Entity
.
包含CrmSvcUtil的GeneratedCode的示例包括:
CrmServiceClient service = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Crm"].ConnectionString);
Contact c = new Contact()
{
LastName = "Test"
};
Guid cOntactId= service.Create(c);
var respOnse= service.Retrieve("contact", contactId, new ColumnSet());
Console.WriteLine($"Type of response from CRM: {response.GetType()}");
Console.WriteLine($"Response from CRM as contact is null? {response as COntact== null}");
输出:
Type of response from CRM: Contact
Response from CRM as contact is null? False
没有生成代码的示例:
CrmServiceClient service = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Crm"].ConnectionString);
Entity c = new Entity("contact");
c["lastname"] = "Test";
Guid cOntactId= service.Create(c);
var respOnse= service.Retrieve("contact", contactId, new ColumnSet());
Console.WriteLine($"Type of response: {response.GetType()}");
输出:
Type of response: Microsoft.Xrm.Sdk.Entity
回到你的问题.如果你在项目中包含生成的代码,Retrieve
那么Contact
无论如何返回一个你只需做一个简单的(Contact)service.Retrieve(...)
转换(例如)或转换(as
).就什么ToEntity
做而言,它实际上并没有进行演员表或转换.它创建一个新对象并在其他一些东西中执行浅拷贝.因此,如果符合您的需要,请使用它,但如果没有它,您可能会离开.
解密代码:
public T ToEntity() where T : Entity
{
if (typeof(T) == typeof(Entity))
{
Entity entity = new Entity();
this.ShallowCopyTo(entity);
return entity as T;
}
if (string.IsNullOrWhiteSpace(this._logicalName))
{
throw new NotSupportedException("LogicalName must be set before calling ToEntity()");
}
string text = null;
object[] customAttributes = typeof(T).GetCustomAttributes(typeof(EntityLogicalNameAttribute), true);
if (customAttributes != null)
{
object[] array = customAttributes;
int num = 0;
if (num
2> Pawel Gradec..:
它总是那样工作,从这里看一下CRM 2011示例代码
ColumnSet cols = new ColumnSet(new String[] { "name", "address1_postalcode", "lastusedincampaign", "versionnumber" });
Account retrievedAccount = (Account)_serviceProxy.Retrieve("account", _accountId, cols);
Console.Write("retrieved ");
这就是你必须EnableProxyTypes();
在你的IOrganizationService 上做的原因.基本上如果你这样做,所有调用都将返回早期绑定类型,而不是Entity对象(当然早期绑定是从Entity继承的,但你知道我的意思).这只是一个从CRM获取数据的功能.
这与ToEntity <>()无关,因为你仍然无法做到这样的事情:
var account = new Entity("account");
var earlyBoundAccount = account as Account; //this will result in NULL
因此,如果您有实体(例如在插件目标或PostImage中),您仍然必须使用ToEntity将其转换为早期绑定.
更新:我深入挖掘并检查了EnableProxyTypes的作用 - 它只是使用DataContractSerializerOperationBehavior类来注入它自己IDataContractSurrogate
来处理响应的序列化/反序列化(例如,如何使用它可以在这里找到).通过查看反序列化的CRM来源,您可以亲眼看到如何实现反序列化:
object IDataContractSurrogate.GetDeserializedObject(object obj, Type targetType)
{
bool supportIndividualAssemblies = this._proxyTypesAssembly != null;
OrganizationResponse organizatiOnResponse= obj as OrganizationResponse;
if (organizationResponse != null)
{
Type typeForName = KnownProxyTypesProvider.GetInstance(supportIndividualAssemblies).GetTypeForName(organizationResponse.ResponseName, this._proxyTypesAssembly);
if (typeForName == null)
{
return obj;
}
OrganizationResponse organizationResponse2 = (OrganizationResponse)Activator.CreateInstance(typeForName);
organizationResponse2.RespOnseName= organizationResponse.ResponseName;
organizationResponse2.Results = organizationResponse.Results;
return organizationResponse2;
}
else
{
Entity entity = obj as Entity;
if (entity == null)
{
return obj;
}
Type typeForName2 = KnownProxyTypesProvider.GetInstance(supportIndividualAssemblies).GetTypeForName(entity.LogicalName, this._proxyTypesAssembly);
if (typeForName2 == null)
{
return obj;
}
Entity entity2 = (Entity)Activator.CreateInstance(typeForName2);
entity.ShallowCopyTo(entity2);
return entity2;
}
}
因此,基本上通过实体逻辑名称获取KnownProxyTypes的类型并使用实例化Activator
.再次 - 这仅适用于您为其启用代理类型的IOrganizationService(并且据我记得,如果代理在同一个程序集中实例化IOrganizationService,则默认情况下启用此功能,即使您没有明确调用它,但是这个我不是百分百肯定的)