【问题标题】:How to manipulate values in LINQ query without "Explicit construction of entity type ### in query is not allowed when trying to modify value" error如何在没有“尝试修改值时不允许在查询中显式构造实体类型###”错误的情况下在 LINQ 查询中操作值
【发布时间】:2010-03-11 11:51:20
【问题描述】:

是否可以从 LINQ 选择查询中更改字段值以用于 ASP.NET MVC 应用程序?

例如,如果查询返回值为“foo”的字段,我希望它的输出为“bar”。

本质上,我希望 LINQ 创建这个 TSQL 语句:

CREATE PROCEDURE GetSpecialCaseOfMyObject (
     @param varchar(10)
     ) AS

SELECT
     REPLACE( FieldA, 'foo', @param ) [FieldA]
     FieldB,
     FieldC
FROM
     MyTable
WHERE
     FieldA = @param

我已经做到了这一点,并且它正在构建,但是......

public IQueryable<MyObject> GetSpecialCaseOfMyObject (string myParam)
{
        var result = from o in Context.MyObject
                     where o.FieldA = myParam
                     select new MyObject
                        {
                                FieldA = o.FieldA.Replace("foo", myParam),
                                FieldB = o.FieldB,
                                FieldC = o.FieldC
                        };

        return result;
}

...当我尝试运行视图以从中返回数据时,我得到一个黄屏死机:

不允许在查询中显式构造实体类型“Model.DataAccess.MyObject”。

我尝试使用匿名类型,但无法将其转换回 MyObject。

我想要做的事情是否可能而不用经历各种麻烦?

【问题讨论】:

    标签: asp.net-mvc linq linq-to-sql


    【解决方案1】:

    如果您有域模型甚至视图模型,这将非常容易。您可以使用AutoMapper 之类的工具来处理大部分繁琐的工作。您所要做的就是创建一个类似于实体模型的类:

    public class MyViewObject
    {
        public MyViewObject(string fieldA, string fieldB, string fieldC)
        {
            this.FieldA = fieldA;
            this.FieldB = fieldB;
            this.FieldC = fieldC;
        }
    
        public string FieldA { get; set; }
        public string FieldB { get; set; }
        public string FieldC { get; set; }
    }
    

    然后映射它(我在这里展示的是手动映射,但正如我所说,您可以使用自动映射工具自动执行很多操作):

    public IEnumerable<MyViewObject> GetViewObjects(string arg)
    {
        var dataObjects = GetMyObjects(arg);
        return dataObjects.Select(o => TransformMyObject(o, "bar"));
    }
    
    public MyViewObject TransformMyObject(MyObject o, string fooReplacement)
    {
        return new MyViewObject(o.FieldA, o.FieldB,
            o.FieldC.Replace("foo", fooReplacement);
    }
    

    这真的不是很多工作,它将很多更容易支持未来对表示逻辑的更改。如果它是非常简单的格式,那么在视图中包含一些这种逻辑也是可以的,但我更喜欢让视图尽可能地哑,视图模型包含大部分(或全部)字符串属性。

    现在看起来像是“跳槽”,但是一旦您拥有一个单独的域和/或视图模型,您会想知道没有一个域和/或视图模型是如何度过的。当您的应用缺少整个层时,您就会开始遇到这些奇怪的泄漏抽象问题。

    【讨论】:

    • 我并不认为它真的是一个抽象问题 - 该应用程序是用单独的 DomainModel、Service、Controller、View 层构建的,并且使用存储库模式,通过 Linq-To-SQL 进行后端。如果我按原样从数据库中读取,我没有问题。我可以用 MyObject 对象进行单元测试没问题。我只是不确定如何在不查询两次的情况下操作这些值。我肯定对这种做事方法还是新手,所以也许我只是误解了显而易见的事情。
    • @Mike:如果你已经有一个域模型,那么这个转换应该在从数据模型到域模型(或从域到视图模型)的映射阶段完成。您无需需要“在输入时”操作这些值 - 您可以在输出的过程中调整它们。
    • 我能够解决我的问题 - 这一切都源于我的映射过程中的错误参考。一旦解决了这个问题,我的初始代码就可以工作了。你的回答让我回过头来用细齿梳子重新审视事物。
    【解决方案2】:

    我不会费心修改查询逻辑。视图的职责是格式化输出。所以让查询保持原样:

    public IQueryable<MyObject> GetMyObject (string myParam)
    {
        return from o in Context.MyObject
               where o.FieldA = myParam
               select o;
    }
    

    并根据需要采用您的视图格式:

    <div><%= Html.Encode(Model.FieldA.Replace("foo", "bar")) %></div>
    

    或者更好的写一个助手:

    public static string FormatFieldA(this MyObject myObject)
    {
        return myObject.FieldA.Replace("foo", "bar");
    }
    

    可以用作:

    <div><%= Html.Encode(Model.FormatFieldA()) %></div>
    

    【讨论】:

    • 好的,但是如果我想使用变量而不是文字进行替换怎么办,例如 Replace("foo", myParam)。如果我将其卸载到 View,我现在需要传入 ViewData,对吗?如果有任何方法可以操纵数据对象本身并让我想要的值冒泡到视图中,那么这样做就感觉不对。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多