如何在OData的EF Code First模型中隐藏标识列

时间:2012-08-07 16:59:09

标签: c# entity-framework odata

这实际上是一个EF Code First问题,但有时OData的上下文会有所不同。问题很简单。我们的基础SQL Server表/视图将Identity列作为(代理)主键。它们还有一个“代码”字段,代表用户熟悉的唯一标识符。简单示例:CarModel:Id = 3,Code ='Ford'; 我已成功创建EF模式和OData以使用“代码”字段作为导航键进行导航,使用数据注释,并且基础表/视图在这些列上具有索引,因此这是可接受的。但我真的希望将Id列作为键,并将其作为模型中的导航属性,但不会将其显示在响应中。也许这就是OData部分有所作为的地方,因为我宁愿不做任何复杂的拦截和重新塑造响应。将列设置为“private”或甚至“internal”会在模型生成期间引发错误:“表X没有定义键”

是否可以在EF模型中定义标识列,但不能将其作为OData实体/响应的一部分?


修改

所以,我在下面的评论仍然有效。这对于标识/键列来说既不是一个好主意,也不会“隐藏”它们允许模型正确编译。但是,感谢来自@mreyeros的一些链接和来自Vitek Karas的social.msdn帖子,这里有一些注意事项。 System.Data.Services命名空间具有IgnorePropertiesAttribute。它允许模型中的属性“隐藏”。但是,正如Vitek所说,它目前仅适用于ReflectionProvider,而不适用于EF。 (如果您使用的是NuGet托管版本,则需要确保引用正确的库。

也就是说,流畅的配置API 在EF / OData中工作:

modelBuilder.Entity<Foo>().Ignore(f => f.Password);

但是,它不仅隐藏了响应中的属性,还将其隐藏在模型和数据库中(对于只读查询模型可能没问题)。因此,如果将导航键标记为隐藏,则模型将无法编译。如果您将任何其他属性标记为隐藏,但在QueryInterceptor中引用它,则会抛出异常。

2 个答案:

答案 0 :(得分:0)

我不是100%确定是否是这种情况但是,如果您将“ScaffoldColumn(false)”属性应用于要隐藏的属性,它可能会起作用。以下是该属性的MSDN条目

答案 1 :(得分:0)

您需要做的是创建一个odata控制器,它返回原始实体的预计子集。

//in WebApi Config Method
config.MapHttpAttributeRoutes();

ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<FullEntity>("FullData");
builder.EntitySet<SubsetEntity>("SubsetData");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());


config.Routes.MapHttpRoute(
  name: "DefaultApi",
  routeTemplate: "api/{controller}/{action}/{id}",
  defaults: new { id = RouteParameter.Optional, action = "GET" }
);
SetupJsonFormatters();
config.Filters.Add(new UncaughtErrorHandlingFilterAttribute());

...然后有一个用于FulLData的两个Odata控制器,一个用于SubsetData(具有不同的安全性),

namespace myapp.Web.OData.Controllers
{
    public class SubsetDataController : ODataController
    {
        private readonly IWarehouseRepository<FullEntity> _fullRepository;
        private readonly IUserRepository _userRepository;

        public SubsetDataController(
            IWarehouseRepository<fullEntity> fullRepository,
            IUserRepository userRepository
            )
        {
            _fullRepository = fullRepository;
            _userRepository = userRepository;
        }

public IQueryable<SubsetEntity> Get()
        {
            Object webHostHttpRequestContext = Request.Properties["MS_RequestContext"];
            System.Security.Claims.ClaimsPrincipal principal =
                (System.Security.Claims.ClaimsPrincipal)
                    webHostHttpRequestContext.GetType()
                        .GetProperty("Principal")
                        .GetValue(webHostHttpRequestContext, null);
            if (!principal.Identity.IsAuthenticated)
                throw new Exception("user is not authenticated cannot perform OData query");

            //do security in here

            //irrelevant but this just allows use of data by Word and Excel.
            if (Request.Headers.Accept.Count == 0)
                Request.Headers.Add("Accept", "application/atom+xml");

            return _fullRepository.Query().Select( b=>
                    new SubsetDataListEntity
                    {
                        Id = b.Id,
                        bitofData = b.bitofData
                    }
          } //end of query
   } //end of class