为什么在我 运行 我的 LINQ 查询之后我的部分 class 的属性是空的?
Why are the properties of my partial class empty after I've run my LINQ query?
我正在通过 SDK 从 Dynamics CRM 2011 中提取项目实体列表,如下所示:
var projects = (from project in Context.ProjectSet
where project.ModifiedOn > DateTime.Now.AddHours(-1)
select new Project
{
Id = project.Id
}).ToList();
这很好用,returns 正确的项目数量及其 ID。
项目 class 由 CrmSvcUtil.exe 自动生成并存储在部分 class 中,如下所示:
Entities.cs
(实际文件比较大,我删减了)
[assembly: Microsoft.Xrm.Sdk.Client.ProxyTypesAssembly()]
namespace Framework.CRM
{
public partial class Project : Microsoft.Xrm.Sdk.Entity, System.ComponentModel.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged
{
// There are lots of properties and events etc here
// Here's one example of a property for brevity
[Microsoft.Xrm.Sdk.AttributeLogicalName("createdby")]
public Microsoft.Xrm.Sdk.EntityReference CreatedBy
{
get
{
return GetAttributeValue<Microsoft.Xrm.Sdk.EntityReference>("createdby");
}
}
}
}
几个自动生成的属性没有 setter,所以当我 运行 我的查询时我无法存储它们的值。因为它是自动生成的代码,所以我没有修改它,而是用一些额外的属性扩展了 class,例如:
CustomProperties.cs
namespace Framework.CRM
{
using System;
public partial class Project
{
public Guid CustomerGuid { get; set; }
public DateTime? LastUpdated { get; set; }
// It's only the nullable DateTime because CRM implements
// that for some reason even though it's never null
}
}
我现在可以使用相同的查询,但这次我可以存储一些以前不能存储的属性:
var projects = (from project in Context.ProjectSet
where project.ModifiedOn > DateTime.Now.AddHours(-1)
select new Project
{
Id = project.Id,
LastUpdated = project.ModifiedOn,
CustomerGuid = project.CompanylinkId != null ? project.CompanylinkId.Id : Guid.Empty
}).ToList();
这仍然获取了正确数量的项目并且填充了 Id
属性 但是 我的所有自定义属性都是空的,我不明白为什么 .我可以向您保证 ModifiedOn
和 CompanylinkId
在 CRM 中不为空。
例如:
foreach (var project in projects)
{
Console.WriteLine(project.Id.ToString());
Console.WriteLine(project.LastUpdated?.ToString("dd/MM/yyyy"));
}
输出:
{40e74702-d17b-4598-b4a0-150b353459a4}
{134aa5bd-aef3-4489-93c2-a3c0bdebd20a}
预计:
{40e74702-d17b-4598-b4a0-150b353459a4}
18/11/2016
{134aa5bd-aef3-4489-93c2-a3c0bdebd20a}
17/11/2016
更令人沮丧的是,这在我上次执行时有效,而且我将旧项目与新项目并排放置,看不到我必须做些什么来修复它。 我是否错误地使用了部分 classes 与 LINQ 查询的结合?
编辑:
有趣的是,如果我将查询更改为 select 现有项目而不是创建一个新项目,它就可以正常工作:
var projects = (from project in Context.ProjectSet
where project.ModifiedOn > DateTime.Now.AddHours(-1)
select project).ToList();
我真的不想这样做,因为我只想要数百个字段中的大约六个字段,这相当于 select * from
。
这是我对标准 CrmSvcUtil 生成的 classes 的不满之一。它们不允许设置只读字段,除非您检索整个 class,这是一种不好的做法。
为了帮助克服这个问题,我在 XrmToolBox 的 EarlyBoundGenerator 中写了一个更改为“Generate AnonymousType Constructors”
/// <summary>
/// Constructor for populating via LINQ queries given a LINQ anonymous type
/// <param name="anonymousType">LINQ anonymous type.</param>
/// </summary>
[System.Diagnostics.DebuggerNonUserCode()]
public Project(object anonymousType) :
this()
{
foreach (var p in anonymousType.GetType().GetProperties())
{
var value = p.GetValue(anonymousType, null);
var name = p.Name.ToLower();
if (name.EndsWith("enum") && value.GetType().BaseType == typeof(System.Enum))
{
value = new Microsoft.Xrm.Sdk.OptionSetValue((int) value);
name = name.Remove(name.Length - "enum".Length);
}
switch (name)
{
case "id":
base.Id = (System.Guid)value;
Attributes["projectid"] = base.Id;
break;
case "productid":
var id = (System.Nullable<System.Guid>) value;
if(id == null){ continue; }
base.Id = id.Value;
Attributes[name] = base.Id;
break;
case "formattedvalues":
// Add Support for FormattedValues
FormattedValues.AddRange((Microsoft.Xrm.Sdk.FormattedValueCollection)value);
break;
default:
Attributes[name] = value;
break;
}
}
}
这样您就可以将查询更改为如下内容:
var projects = (from project in Context.ProjectSet
where project.ModifiedOn > DateTime.Now.AddHours(-1)
select new Project(new {
{
project.Id,
project.ModifiedOn,
project.CompanylinkId
}).ToList();
这有两件大事:
- 无需指定属性名称两次
- 现在可以填充只读字段,不再需要自定义属性!
如果您愿意,您可以复制并粘贴构造函数,切换到使用 EarlyBoundGenerator,或者更直接地回答您关于为什么您的值没有被填充的问题,很可能是因为您实际上并没有将值放入实体的 AttributeCollection 属性 中。从实体转换为您定义的类型时,CRM 会进行一些有趣的优化。
我正在通过 SDK 从 Dynamics CRM 2011 中提取项目实体列表,如下所示:
var projects = (from project in Context.ProjectSet
where project.ModifiedOn > DateTime.Now.AddHours(-1)
select new Project
{
Id = project.Id
}).ToList();
这很好用,returns 正确的项目数量及其 ID。
项目 class 由 CrmSvcUtil.exe 自动生成并存储在部分 class 中,如下所示:
Entities.cs
(实际文件比较大,我删减了)
[assembly: Microsoft.Xrm.Sdk.Client.ProxyTypesAssembly()]
namespace Framework.CRM
{
public partial class Project : Microsoft.Xrm.Sdk.Entity, System.ComponentModel.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged
{
// There are lots of properties and events etc here
// Here's one example of a property for brevity
[Microsoft.Xrm.Sdk.AttributeLogicalName("createdby")]
public Microsoft.Xrm.Sdk.EntityReference CreatedBy
{
get
{
return GetAttributeValue<Microsoft.Xrm.Sdk.EntityReference>("createdby");
}
}
}
}
几个自动生成的属性没有 setter,所以当我 运行 我的查询时我无法存储它们的值。因为它是自动生成的代码,所以我没有修改它,而是用一些额外的属性扩展了 class,例如:
CustomProperties.cs
namespace Framework.CRM
{
using System;
public partial class Project
{
public Guid CustomerGuid { get; set; }
public DateTime? LastUpdated { get; set; }
// It's only the nullable DateTime because CRM implements
// that for some reason even though it's never null
}
}
我现在可以使用相同的查询,但这次我可以存储一些以前不能存储的属性:
var projects = (from project in Context.ProjectSet
where project.ModifiedOn > DateTime.Now.AddHours(-1)
select new Project
{
Id = project.Id,
LastUpdated = project.ModifiedOn,
CustomerGuid = project.CompanylinkId != null ? project.CompanylinkId.Id : Guid.Empty
}).ToList();
这仍然获取了正确数量的项目并且填充了 Id
属性 但是 我的所有自定义属性都是空的,我不明白为什么 .我可以向您保证 ModifiedOn
和 CompanylinkId
在 CRM 中不为空。
例如:
foreach (var project in projects)
{
Console.WriteLine(project.Id.ToString());
Console.WriteLine(project.LastUpdated?.ToString("dd/MM/yyyy"));
}
输出:
{40e74702-d17b-4598-b4a0-150b353459a4}
{134aa5bd-aef3-4489-93c2-a3c0bdebd20a}
预计:
{40e74702-d17b-4598-b4a0-150b353459a4}
18/11/2016
{134aa5bd-aef3-4489-93c2-a3c0bdebd20a}
17/11/2016
更令人沮丧的是,这在我上次执行时有效,而且我将旧项目与新项目并排放置,看不到我必须做些什么来修复它。 我是否错误地使用了部分 classes 与 LINQ 查询的结合?
编辑:
有趣的是,如果我将查询更改为 select 现有项目而不是创建一个新项目,它就可以正常工作:
var projects = (from project in Context.ProjectSet
where project.ModifiedOn > DateTime.Now.AddHours(-1)
select project).ToList();
我真的不想这样做,因为我只想要数百个字段中的大约六个字段,这相当于 select * from
。
这是我对标准 CrmSvcUtil 生成的 classes 的不满之一。它们不允许设置只读字段,除非您检索整个 class,这是一种不好的做法。
为了帮助克服这个问题,我在 XrmToolBox 的 EarlyBoundGenerator 中写了一个更改为“Generate AnonymousType Constructors”
/// <summary>
/// Constructor for populating via LINQ queries given a LINQ anonymous type
/// <param name="anonymousType">LINQ anonymous type.</param>
/// </summary>
[System.Diagnostics.DebuggerNonUserCode()]
public Project(object anonymousType) :
this()
{
foreach (var p in anonymousType.GetType().GetProperties())
{
var value = p.GetValue(anonymousType, null);
var name = p.Name.ToLower();
if (name.EndsWith("enum") && value.GetType().BaseType == typeof(System.Enum))
{
value = new Microsoft.Xrm.Sdk.OptionSetValue((int) value);
name = name.Remove(name.Length - "enum".Length);
}
switch (name)
{
case "id":
base.Id = (System.Guid)value;
Attributes["projectid"] = base.Id;
break;
case "productid":
var id = (System.Nullable<System.Guid>) value;
if(id == null){ continue; }
base.Id = id.Value;
Attributes[name] = base.Id;
break;
case "formattedvalues":
// Add Support for FormattedValues
FormattedValues.AddRange((Microsoft.Xrm.Sdk.FormattedValueCollection)value);
break;
default:
Attributes[name] = value;
break;
}
}
}
这样您就可以将查询更改为如下内容:
var projects = (from project in Context.ProjectSet
where project.ModifiedOn > DateTime.Now.AddHours(-1)
select new Project(new {
{
project.Id,
project.ModifiedOn,
project.CompanylinkId
}).ToList();
这有两件大事:
- 无需指定属性名称两次
- 现在可以填充只读字段,不再需要自定义属性!
如果您愿意,您可以复制并粘贴构造函数,切换到使用 EarlyBoundGenerator,或者更直接地回答您关于为什么您的值没有被填充的问题,很可能是因为您实际上并没有将值放入实体的 AttributeCollection 属性 中。从实体转换为您定义的类型时,CRM 会进行一些有趣的优化。