我正在开发一个使用EF进行数据库访问的库。为了避免将实体暴露在库外,我已将所有表的访问权限设置为内部(我还将实体容器访问设置为内部)。现在的问题是,在库中,当我试图通过实体id获取实体时,Where
查询会抛出异常,我不知道为什么。
内部访问已经在图表(.edmx文件)中设置,在我用作库内工厂的静态类中,我有这样的东西:
var id = 1234;
var mec = new MyEntitiesContainer();
var myEntity = mec.MyEntities.Where(e => e.MyEntitiesId == id).FirstOrDefault();
通过id从数据库中获取具体实体(行)的简单where查询。
当所有实体类访问都是公共的时,没有问题,但当我将它们设置为内部时,会抛出此异常:
System.ArgumentNullException: Value cannot be null. Parameter name: source
at System.Linq.Queryable.Where[TSource](IQueryable`1 source, Expression`1 predicate)
有什么建议吗?
更新实际上找到了一个更直接的解决方案:
- 在设计器中打开edmx
- 将"实体容器访问"设置为内部
- 确保所有实体的"访问权限"都设置为"公共">
- 展开edmx并编辑实体t4(不是*.Context.tt)
- 在t4中,搜索
Accessibility.ForType(entity)
并将其替换为"Internal"
(或为VB搜索"Friend"
) - 保存/重新运行T4,仅此而已
遵循这些步骤后,您的EF项目的任何部分都不应在大会外可见,一切都应"正常工作"。
如果您仍然遇到"Value cannot be null"异常,请参阅本文底部的"gotcha"。
这里已经回答了这个问题:c#DbSet-内部对象无法获得
要点是,如果将entityset/dbset属性设置为内部,则EF不会自动实例化它。但您可以手动实例化它,如该页面上已接受的答案中所述。
另一个需要注意的问题:
VS2012中有一个错误(11.0.60610.01更新3是我当前的环境),设计器不会正确地将基础edmx文件中的项设置回Public,即使它报告的情况是这样的。
因此,即使在将项设置回public、重新运行上下文t4并重新构建之后,您仍然会收到该异常。
我找到的唯一解决方法是打开edmx文件并手动编辑它,将内部设置回public。
来自另一个命名空间的代码如何设置命名空间中对象的属性?如果您想一想EF是如何生活在与代码不同的名称空间中,并在其中填充属性的,我敢说public
在某种程度上是必要的。