Entity Framework - “Unable to create a constant value of type 'Closure type'…” error

前端 未结 4 988
感情败类
感情败类 2020-11-27 19:07

Why do I get the error:

Unable to create a constant value of type \'Closure type\'. Only primitive types (for instance Int32, String and Guid) are s

4条回答
  •  野性不改
    2020-11-27 20:02

    I've spent the last 6 months battling this limitation with EF 3.5 and while I'm not the smartest person in the world, I'm pretty sure I have something useful to offer on this topic.

    The SQL generated by growing a 50 mile high tree of "OR style" expressions will result in a poor query execution plan. I'm dealing with a few million rows and the impact is substantial.

    There is a little hack I found to do a SQL 'in' that helps if you are just looking for a bunch of entities by id:

    private IEnumerable getByIds(IEnumerable ids)
    {
        string idList = string.Join(",", ids.ToList().ConvertAll(id => id.ToString()).ToArray());
        return dbContext.Entity1.Where("it.pkIDColumn IN {" + idList + "}");
    }
    

    where pkIDColumn is your primary key id column name of your Entity1 table.

    BUT KEEP READING!

    This is fine, but it requires that I already have the ids of what I need to find. Sometimes I just want my expressions to reach into other relations and what I do have is criteria for those connected relations.

    If I had more time I would try to represent this visually, but I don't so just study this sentence a moment: Consider a schema with a Person, GovernmentId, and GovernmentIdType tables. Andrew Tappert (Person) has two id cards (GovernmentId), one from Oregon (GovernmentIdType) and one from Washington (GovernmentIdType).

    Now generate an edmx from it.

    Now imagine you want to find all the people having a certain ID value, say 1234567.

    This can be accomplished with a single database hit with this:

    dbContext context = new dbContext();
    string idValue = "1234567";
    Expression> expr =
        person => person.GovernmentID.Any(gid => gid.gi_value.Contains(idValue));
    
    IEnumerable people = context.Person.AsQueryable().Where(expr);
    

    Do you see the subquery here? The generated sql will use 'joins' instead of sub-queries, but the effect is the same. These days SQL server optimizes subqueries into joins under the covers anyway, but anyway...

    The key to this working is the .Any inside the expression.

提交回复
热议问题