OData或Code First失败:派生的导航属性

本文关键字:派生 导航 属性 失败 Code First OData | 更新日期: 2023-09-27 18:23:40

我遇到了一个复杂的情况,要么我的项目的代码优先部分有问题,要么我项目的OData部分有问题。。。

我有一个抽象类Person,从中导出两个类UserDriver

[DataContract]
[KnownType(typeof(User))]
[KnownType(typeof(Driver))]
public abstract class Person
{
    [Key, DataMember]
    public int ID { get; set; }
    [DataMember]
    public int RelationID { get; set; }
}
public class User : Person { }
public class Driver : Person { } // shortened for sake of readability

现在我有了一个模型Relation,它可以包含用户和/或驱动程序。

[DataContract]
public class Relation
{
    [Key, DataMember]
    public int ID { get; set; }
    [DataMember]
    public virtual ICollection<User> Users { get; set; }
    [DataMember]
    public virtual ICollection<Driver> Drivers { get; set; }
}

问题是,当我让Code First生成迁移代码时,我可以看到它想要添加两列Relation_IDRelation_ID1,以处理UsersDrivers的映射。我将[InverseProperty("ID")]属性应用于两个导航属性,以便尝试解决此问题(如本文所述:Code First DataAnnotations)。但问题依然存在。所以,这是行不通的。

现在,您会说:为什么不将其设为ICollection<Person> People属性,并使用this.db.People.OfType<User>()将对象强制转换到正确的模型并以这种方式检索它呢。这是完全可以接受的,但现在它变成了OData问题。

我希望能够从Relations控制器调用public IQueryable<User> GetUsers([FromODataUri] int key),以便使用/odata/Relations(16)/Users从关系中获取所有用户。如果Relation模型中不存在Users属性,OData解析器将拒绝任何此类调用,因为它无法解析为正确的方法。

所以我被夹在两个世界的设计之间。我猜,为了正确地解决这个问题,重点应该放在代码第一部分,而不是OData部分。任何想法都很感激,提前谢谢!

OData或Code First失败:派生的导航属性

您还可以添加ICollection People属性,并从数据模型中排除Users和Drivers属性。例如,

[DataContract]
public class Relation
{
    [Key, DataMember]
    public int ID { get; set; }
    [DataMember]
    public virtual ICollection<Person> People { get; set; }      
    [DataMember]
    public virtual ICollection<User> Users
    {
        get
        {
            return People.OfType<User>();
        }
    }
    [DataMember]
    public virtual ICollection<Driver> Drivers
    {
        get
        {
            return People.OfType<Driver>();
        }
    }
}

在您的DbModelBuilder代码中,通过执行排除用户和驱动程序属性

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        var relation = modelBuilder.Entity<Relation>();
        relation.Ignore(p => p.Users);
        relation.Ignore(p => p.Drivers);
    }

在ODataModelBuilder中,如果需要,请排除People属性。