3
votes

I'm trying to figure out how to use a NotMapped property with OData

I have this User Model:

[DataContract]
public class User
{
[DataMember]
public long Id { get; set; }
[DataMember]
public virtual InstagramUser InstagramUser { get; set; }
[DataMember]
public virtual FacebookUser FacebookUser { get; set; }
[NotMapped]
public string InstagramID { get; set; 
}

And I have this GetAll() method in the User Controller

public IQueryable<User> GetAllUsers()
{
       _repository = new UserRepository();
       return _repository.GetAll().AsQueryable();
 }

and this GetAll() function in the User repository

public IQueryable<User> GetAll()
{
     InstaStoryDB db = new InstaStoryDB();
     var ret = db.Users.Include("InstagramUser").Include("FacebookUser").AsQueryable();
     foreach(User user in ret)
     {
        user.InstagramID = user.InstagramUser.InstagramID; //<-- I'm adding here the value to the property
     }
     return ret;         
}

And this is the InstagramUser Model

[DataContract]
public class InstagramUser
{
[DataMember]
public long UserId { get; set; }
[DataMember]
public string InstagramID { get; set; 
}

All Working good.

I did a change to the User model and added the InstagramUser that contain the InstagramID, so I added [NotMapped] attribute to remove the InstagramID from the User table in the DB since the InstagramUser already contain the InstagramID.

When ever I try to use Odata like this: localhost:555/api/users/?$filter=InstagramID eq '456456546' It's failed and return an error that the InstagramID property is not exist.

what can I do to use filter with Odata on NotMapped property?

3
I guess you cannot use NotMapped property. NotMappet property is not described in your model and so it is not available for querying when you use EF provider for OData service.Ladislav Mrnka
That what I thought, I'm adding a fix in the question.. can you look at it now?Ofear

3 Answers

9
votes

This worked for me using OData v4 in Web API:

var t = modelBuilder.StructuralTypes.First(x => x.ClrType == typeof(User));
t.AddProperty(typeof(User).GetProperty("InstagramID"));
4
votes

You can find the fix here : http://forums.asp.net/t/1887669.aspx?OData+EF+Model+with+custom+calculated+properties

  1. First process the odata query manually
  2. use a select query to add the notmapped property

For example

public IQueryable<DomainModel> GetAllDomains(ODataQueryOptions<Domains> queryOptions)
    {
        var query = queryOptions.ApplyTo(objectContext.Domains) as IQueryable<Domain>;
        return query.AsEnumerable().Select(d => new DomainModel
        {
            Name = d.Name,
            Activated = d.Activated,
            Address = d.Address,
            AdminUserName = d.AdminUserName,
            DateCreated = d.DateCreated,
            Enabled = d.Enabled,
            Subscription = (SubscriptionTypes)d.SubscriptionType,
            Website = d.Website,
            StatsUpdatePending = d.StatsUpdatePending,
            LastHousekeeping = d.LastHousekeeping,
            CalculatedProperty = calculator.Calculate(d.Name, d.Activated)
        }).AsQueryable();
    }
3
votes

I found a similar solution to Jason Steele one but using the methods EntityType and Property like this:

modelBuilder.EntityType<User>().Property(u => u.InstagramID);

There result is the same. If you look at the source code of the Property method, you will find that it is getting the PropertyInfo and then adding it to the StructuralTypeConfiguration of that class:

PropertyInfo propertyInfo = PropertySelectorVisitor.GetSelectedProperty(propertyExpression);
PrimitivePropertyConfiguration property = _configuration.AddProperty(propertyInfo);