Reputation: 3520
This is really an EF Code First question, but sometimes the context of OData makes a difference. The question is simple. Our underlying SQL Server tables/views have Identity columns as the (surrogate) primary key. They also have a 'code' field which represent unique identifiers which users are familiar with. Simple example: CarModel: Id = 3, Code = 'Ford'; I have successfully create the EF Mode and OData to navigate using the 'Code' field as the navigation key, using Data Annotations, and the underlying tables/views have indexes on those columns, so this is acceptable. But I would really like to have the Id column as the key, and as the navigation property in the model, but not have it show up in the response. Perhaps this is where the OData part makes a difference, because I would prefer not to do any complex interception and re-shaping of the response. Setting the columns to 'private' or even 'internal' throws an error during model generation: 'Table X has no key defined'
Is it possible to define an identity column in the EF Model, but not have it part of the OData entity/response?
Edit:
So, my comment below is still valid. This is both not a good idea for identity/key columns, nor would 'hiding' them allow the model to compile correctly. However, thanks to some links from @mreyeros and a social.msdn post from Vitek Karas, here are some notes.
The System.Data.Services namespace has an IgnorePropertiesAttribute
. It allows properties in your model to be 'hidden'. However, as Vitek says, it currently only works with the ReflectionProvider, not with EF. (And you need to make sure you are referencing the correct library if you are using a NuGet managed release.
That said, the fluent configuration API will work in EF/OData:
modelBuilder.Entity<Foo>().Ignore(f => f.Password);
However, not only does it hide a property in the response, it also hides it from the model and the database (which might be okay for read-only query models). So if you mark a navigation key as hidden, the model will not compile. And if you mark any other property as hidden, but reference it in a QueryInterceptor, an exception will be thrown.
Upvotes: 0
Views: 4724
Reputation:
What you need to do is make an odata controller that returns a projected subset of the original entity.
//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());
... then have two Odata Controllers one for FulLData, one for SubsetData (with different security),
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
Upvotes: 2