Xrm Sdk defines一个ToEntity<T>
方法。我一直用它来从CRM中获取早期绑定的实体。今天我正在审查一些代码并看到实体刚刚被投射:
var contact = service.Retrieve("contact", id, new ColumnSet()) as Contact;
我甚至都不知道这是可能的。是否还需要ToEntity调用?
答案 0 :(得分:6)
除此之外,这不是特定的演员,它是转换,转换的行为与直接演员的行为略有不同。
您可以使用as运算符在兼容的引用类型或可空类型之间执行某些类型的转换... as运算符就像转换操作。但是,如果转换不可能,则返回null而不是引发异常。
我假设您的Contact
是由CrmSvcUtil创建的类,例如public partial class Contact : Microsoft.Xrm.Sdk.Entity
,service.Retrieve
为IOrganizationService.Retrieve,其返回类型为Entity
。
Contact
是基类Entity
的派生类。您不能将基类强制转换为更具体的派生类(请参阅Is it possible to assign a base class object to a derived class reference with an explicit typecast in 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
因此{@ 1}}返回Retrieve
,而Entity
无法投放到Contact
,您的代码行(var contact = service.Retrieve("contact", id, new ColumnSet()) as Contact;
)如何工作?< / p>
这是它的神奇之处。显然,如果在应用程序中包含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(...)
)或转换({{1} })。就as
做什么而言,它实际上并没有进行演员表或转换。它创建一个新对象并在其他一些东西中执行浅拷贝。因此,如果符合您的需要,请使用它,但如果没有它,您可能会离开。
反编译代码:
ToEntity
答案 1 :(得分:5)
它始终如此工作,请查看来自here
的CRM 2011示例代码ColumnSet cols = new ColumnSet(new String[] { "name", "address1_postalcode", "lastusedincampaign", "versionnumber" });
Account retrievedAccount = (Account)_serviceProxy.Retrieve("account", _accountId, cols);
Console.Write("retrieved ");
这就是您必须在IOrganizationService上执行EnableProxyTypes();
的原因。基本上如果你这样做,所有调用都将返回早期绑定类型,而不是Entity对象(当然早期绑定是从Entity继承的,但你知道我的意思)。这只是关于从CRM获取数据的一项功能。
这与ToEntity&lt;&gt;()无关,因为你仍然无法做到这样的事情:
var account = new Entity("account");
var earlyBoundAccount = account as Account; //this will result in NULL
因此,如果您有实体(例如在插件目标或PostImage中),您仍然必须使用ToEntity将其转换为早期绑定。
更新:
我深入挖掘并检查了EnableProxyTypes的作用 - 它只是使用DataContractSerializerOperationBehavior类来注入它自己的IDataContractSurrogate
来处理响应的序列化/反序列化(例如如何使用它可以找到{ {3}})。通过查看反序列化的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,即使您没有明确调用它,默认情况下也会启用此功能,但是这个我不是100%肯定的)