C# Include返回的实体框架限制属性

C# Include返回的实体框架限制属性,c#,asp.net-web-api,entity-framework-5,C#,Asp.net Web Api,Entity Framework 5,我使用Include()将相关对象添加到查询结果中。但是,我不希望结果集中包含相关表的所有字段。我已经设法想出了下面的解决方案,这是可行的,但是没有更好的方法来做到这一点吗 由于客户端的限制,我不能返回一个新类型,只返回想要的字段。我需要返回正确的类型(Models.Message) private void LimitProperties(对象实体,列表keeprops){ if(实体==null) { 返回; } PropertyInfo[]props=entity.GetType().Ge

我使用Include()将相关对象添加到查询结果中。但是,我不希望结果集中包含相关表的所有字段。我已经设法想出了下面的解决方案,这是可行的,但是没有更好的方法来做到这一点吗

由于客户端的限制,我不能返回一个新类型,只返回想要的字段。我需要返回正确的类型(Models.Message)

private void LimitProperties(对象实体,列表keeprops){
if(实体==null)
{
返回;
}
PropertyInfo[]props=entity.GetType().GetProperties();
foreach(PropertyInfo props in props)
{
如果(!keeprops.Contains(prop.Name))
{
prop.SetValue(实体,空);
}
}
}
公共模型。消息GetMessageByID(int-messageID){
列表_validProps=新列表{“ID”、“Name”、“Title”};
Models.Message Message=DbContext.Messages
.包括(m=>m.RefChannel)
.包括(m=>m.RefSender)
.包括(m=>m.折射率)
.FirstOrDefault(m=>m.ID==messageID);
//限制返回字段的数量
如果(消息!=null)
{
LimitProperties(message.RefChannel,_validProps);
LimitProperties(message.RefSender,_validProps);
LimitProperties(message.RefRecipient,_validProps);
}
返回消息;
}

以这种方式将类型为
RefSender
的对象与一些
null
值一起使用风险太大。因为不清楚它是真正的空值还是未加载的空值

据我所知,您担心的是序列化对象过于丰富,将用作网络上的dto。在这种情况下,您可以使用一个
自定义序列化程序
,您可以忽略字段以不参与序列化,甚至可以使用一些属性(如[NonSerialize])来忽略某些字段


同样如前所述,在您所说的情况下,一种解决方案是创建一个基类
EntityBase
,其中包含
Id
Name
Title
我最后向查询中添加了
AsNoTracking()
。到目前为止,我还没有看到任何副作用。我只需要确保从客户端发送(返回)的消息设置了所有必需的属性(但这是正常的)

完整代码:

private void LimitProperties(object entity, List<string> keepProps) {
    if (entity == null)
    {
        return;
    }

    PropertyInfo[] props = entity.GetType().GetProperties();
    foreach (PropertyInfo prop in props)
    {
        if (!keepProps.Contains(prop.Name))
        {
            prop.SetValue(entity, null);
        }
    }
}

public Models.Message GetMessageByID(int messageID) {
    List<string> _validProps = new List<string> { "ID", "Name", "Title" };

    Models.Message message = DbContext.Messages
        .Include(m => m.RefChannel)
        .Include(m => m.RefSender)
        .Include(m => m.RefRecipient)
        .AsNoTracking()
        .FirstOrDefault(m => m.ID == messageID);

    // limit the number of returned fields
    if (message != null)
    {
        LimitProperties(message.RefChannel, _validProps);
        LimitProperties(message.RefSender, _validProps);
        LimitProperties(message.RefRecipient, _validProps);
    }

    return message;
}
private void LimitProperties(对象实体,列表keeprops){
if(实体==null)
{
返回;
}
PropertyInfo[]props=entity.GetType().GetProperties();
foreach(PropertyInfo props in props)
{
如果(!keeprops.Contains(prop.Name))
{
prop.SetValue(实体,空);
}
}
}
公共模型。消息GetMessageByID(int-messageID){
列表_validProps=新列表{“ID”、“Name”、“Title”};
Models.Message Message=DbContext.Messages
.包括(m=>m.RefChannel)
.包括(m=>m.RefSender)
.包括(m=>m.折射率)
.AsNoTracking()
.FirstOrDefault(m=>m.ID==messageID);
//限制返回字段的数量
如果(消息!=null)
{
LimitProperties(message.RefChannel,_validProps);
LimitProperties(message.RefSender,_validProps);
LimitProperties(message.RefRecipient,_validProps);
}
返回消息;
}

我可以问您为什么不想设置某些属性吗?例如,发件人对象包含不应传输给其他用户(接收邮件的用户)的用户数据,真的没有其他方式吗?这是非常令人讨厌的。您有保存修改过的实体的风险。您不能让客户端接收
imessage
?您是否尝试使用继承的类?您将创建一个仅具有基本属性的类,而不是一个具有扩展属性的类—您并不总是希望发送的类。然后让扩展类从基类中继承。当您将此任务简化时,请将属性强制转换为基类。@Gabriel Monteiro Nepomuceno:这可能会起作用,但这意味着我必须从基类继承消息,并将RefChannel、RefSender和refrefrefreficient映射到基类。我不确定这是否比我的解决方案好。是的,我也考虑过修改序列化,但我不确定如何将其作为选项添加到WebAPI/MVC管道中(在这种情况下使用自定义序列化程序,在正常情况下使用默认序列化程序)。我不确定我是否理解风险。调用SaveChanges()会将包含对象的空值提交到数据库吗?@mhu-Yep。。正如你提到的,这就是风险。事实上,有一个空值,你不知道它是一个假的空值还是用户在界面上设置的空值。我不确定在这种情况下是否有自定义序列化的解决方案。但是您可以有多个具有不同序列化的继承对象。例如'MessageBrief','Message','MessageFull'。所有这些都可以有不同的序列化策略。我是否可以向查询中添加
AsNoTracking()
,以获取消息的非跟踪副本?
AsNoTracking()
将返回分离的对象,但不能保证不会再次将其附加到
DbContext
。事实上,在大多数情况下,都有一个分离的dto,它由客户端加载、修改并返回到服务器,然后将附加到
DbContext
to
SubmitChanges
private void LimitProperties(object entity, List<string> keepProps) {
    if (entity == null)
    {
        return;
    }

    PropertyInfo[] props = entity.GetType().GetProperties();
    foreach (PropertyInfo prop in props)
    {
        if (!keepProps.Contains(prop.Name))
        {
            prop.SetValue(entity, null);
        }
    }
}

public Models.Message GetMessageByID(int messageID) {
    List<string> _validProps = new List<string> { "ID", "Name", "Title" };

    Models.Message message = DbContext.Messages
        .Include(m => m.RefChannel)
        .Include(m => m.RefSender)
        .Include(m => m.RefRecipient)
        .AsNoTracking()
        .FirstOrDefault(m => m.ID == messageID);

    // limit the number of returned fields
    if (message != null)
    {
        LimitProperties(message.RefChannel, _validProps);
        LimitProperties(message.RefSender, _validProps);
        LimitProperties(message.RefRecipient, _validProps);
    }

    return message;
}