【问题标题】:"unable to create a null constant value of type 'anonymous type'" for nullable column in db“无法为 db 中的可空列创建类型为‘匿名类型’的空常量值”
【发布时间】:2014-02-12 06:37:19
【问题描述】:

我正在使用 EF 和 MVC 访问 SQL 数据库中的数据,并希望控制器使用 json 进行通信(使用 Android 中的 REST,因此不使用视图)。

我发现有必要更改控制器以通过匿名对象投影数据以避免主表和引用表之间的循环引用问题,但是当尝试为集合创建 json 时,这导致了一个新问题对象,当基础记录在可选外键字段中包含 null 时。

表用户(例如)有两个外键来编码/描述表语言和国家,语言是强制性的,国家是可选的。

我发现我可以通过测试 null id 成功地将 Country 元素替换为 null。json 出来很好......

{
"UserID": 3,
"UpdatedWhen": null,
"Country": null,
"Language": {
    "LanguageID": 1,
    "LocalName": "English"
    }
}

...但现在发现当我有多个 User 对象要处理时,这不起作用。

    public JsonResult Index()
    {
        var users = from user in db.Users
                    select new
                    {   user.UserID,
                        < snip >
                        user.CreatedWhen,
                        user.UpdatedBy,
                        user.UpdatedWhen,
                        Country = (user.Country == null ? null : new { user.Country.CountryID, user.Country.LocalName }),
                        Language = new { user.Language.LanguageID, user.Language.LocalName } };

        return Json(users.ToList(), JsonRequestBehavior.AllowGet);
    }

从我读到的问题在于我的 .ToList(),它不喜欢 null Country 对象,因为如果我只处理单个用户,例如

    private object projectUser(User user)
    {
        return new
        {
            user.UserID,
            < snip >
            user.UpdatedWhen,
            Country = (user.Country == null ? null : new { user.Country.CountryID, user.Country.LocalName }),
            Language = new { user.Language.LanguageID, user.Language.LocalName } };

...它工作得很好。

我一直在寻找,但根本找不到一个足够相似的例子来说明如何更好地做到这一点,谁能建议一个方法。

提前致谢。

【问题讨论】:

    标签: c# json linq entity-framework asp.net-mvc-4


    【解决方案1】:

    您无法在linq to entity 查询中创建null 常量值,这就是users.ToList() 这行告诉您何时要执行它......

    这个方法private object projectUser(User user) 是有效的,因为user 已经在内存中获取了......

    要解决您的问题,您可以获取数据,然后选择内存中的数据,如下所示:

    var users = (from user in db.Users
                 join country in db.Countries on user.CountryID equals country.ID into joinedList
                 from country in joinedList.DefaultIfEmpty()
                 select new {user, country})
                .ToList()   // your data fetched to memory by this line
                .Select(u => new
                {
                     u.user.UserID,
                     u.user.CreatedWhen,
                     u.user.UpdatedBy,
                     u.user.UpdatedWhen,
                     Country = (u.country == null ? null : new { u.country.CountryID, u.country.LocalName }),
                     Language = new { u.user.Language.LanguageID, u.user.Language.LocalName } }
                })
                .ToList();
    

    作为替代方案,您可以将国家/地区 (anonymouse type) 的属性设置为默认值,而不是 null,如下所示:

    var users = (from user in db.Users
                 join country in db.Countries on user.CountryID equals country.ID into joinedList
                 from country in joinedList.DefaultIfEmpty()
                 select new {
                     user.UserID,
                     user.CreatedWhen,
                     user.UpdatedBy,
                     user.UpdatedWhen,
                     Language = new { user.Language.LanguageID, user.Language.LocalName },
                     Country = new { 
                         CountryID = country == null ? default(Guid) : country.CountryID,  // i assume type of CountryID is Guid
                         LocalName = country == null ? "" : country.LocalName 
                      }
                  })
                  .ToList();
    

    【讨论】:

    • 一个有趣的方法,谢谢。它(第一个)目前并没有完全给出我预期的结果——所有国家都没有结果——但我可以看到你要去哪里。我会玩一点,应该能够调整它来工作。再次感谢。
    • 您的数据有效吗?使用这两个查询,您会得到相同的结果吗?如果是,我认为您的数据或连接条件中有问题,需要检查这部分查询on user.CountryID equals country.ID
    • 数据很好,我将在周末晚些时候回到这部分代码,我正在让 Android 应用程序与 Web 服务通信,稍微复杂一点事实上 Eclipse/Android 在 Linux 上,而 Web 服务在 W7 VMware 客户机中运行,调试起来有点混乱。很快回来(ish)......
    • 似乎无法让它工作,无论我如何工作,linq 都不会返回我想要/期望的内容,所以我只是重新编写了我的代码的整个部分,所以它没有不再需要数据的两个可选部分。是的,我知道这有点像警察,但我需要克服这个问题,这是最快的方法,而且碰巧导致我的主要代码略有简化。感谢您的帮助。
    【解决方案2】:

    打破查询并查看每个步骤的结果,以找出问题是否来自您的数据:

    var UsersQuery = (from user in db.Users
                      join country in db.Countries on user.CountryID equals country.ID into joinedList
                      from country in joinedList.DefaultIfEmpty()
                      select new {user, country})
                      .ToList();   // your data fetched to memory by this line
    
    var Users = UsersQuery.Select(u => new
            {
                 u.user.UserID,
                 u.user.CreatedWhen,
                 u.user.UpdatedBy,
                 u.user.UpdatedWhen,
                 Country = (u.country == null ? null : new { u.country.CountryID, u.country.LocalName }),
                 Language = new { u.user.Language.LanguageID, u.user.Language.LocalName } }
            })
            .ToList();
    

    【讨论】:

    • 检查这部分查询是否正常,user.CountryID equals country.ID
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多