“无法为db中的可空列创建类型为'anonymous type'的空常量值”

时间:2014-02-12 06:37:19

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

我正在使用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 } };

......它运作得很好。

我一直在寻找,但根本找不到一个类似的如何更好地做到这一点的例子,任何人都可以建议一种方式。

提前致谢。

2 个答案:

答案 0 :(得分:1)

您无法在null个查询中创建linq to entity常量值,这就是此行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();

答案 1 :(得分:0)

打破查询,看看每一步的结果是什么,找出问题来自你的数据:

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();