【问题标题】:Entity Framework Include Record with certain value in a Navigation Property实体框架在导航属性中包含具有特定值的记录
【发布时间】:2014-08-12 11:57:09
【问题描述】:

我正在使用 Entity Framework 6 Code First,并且正在使用 Fluent API 配置我的域模型的映射。我看不到如何为表格创建导航属性,这有点棘手。 我有几个会产生噪音的物体,我想在 NoiseRecord 表中记录这些噪音。

我需要某种条件映射,比如:

modelBuilder.Entity<NoiseRecord>().HasRequired(n=>n.Origine.OrigineType()=="Car").WithMany(c=>c.NoiseRecords);

这将是 Car Navigation Property 的映射以避免这种情况,例如,它包括与飞机相关的记录。

这是我的代码

public interface INoisy
{
    int ID {get; set;}
    string OriginType()
    ...
    //And other useful things not related to persistence
}


public class Car : INoisy
{
    ...
    ICollection<NoiseRecord> NoiseRecords { get; set; }
    string OrigineType()
    {
        return "Car";
    }
}

public class Plane : INoisy
{
    ...
    ICollection<NoiseRecord> NoiseRecords {get; set;}
    string OrigineType()
    {
        return "Plane";
    }
}

还有几个其他类也实现了 INoisy。 下面是 NoiseRecord 表。

public class NoiseRecord
{
    public int RecordID {get; set;}
    public INoisy NoiseOrigine {get; set;}
    public double NoiseMagnitude {get; set;}
}

我正在寻找一种使用 Fluent API 实现这一目标的方法。

谢谢!

【问题讨论】:

    标签: c# entity-framework ef-code-first fluent


    【解决方案1】:

    首先,不能将界面用作导航属性。但是您可以使用抽象基类作为噪声来源

    public abstract class NoiseOrigin
    {
        public NoiseOrigin()
        {
            this.NoiseRecords = new Collection<NoiseRecord>();
        }
    
        public int Id { get; set; }
    
        public ICollection<NoiseRecord> NoiseRecords { get; set; }
    }
    
    public class Car : NoiseOrigin {}
    
    public class Plane : NoiseOrigin { }
    
    public class NoiseRecord
    {
        public int Id { get; set; }
    
        public int OriginId { get; set; }
        public NoiseOrigin Origin { get; set; }
    
        public double NoiseMagnitude { get; set; }
    }
    

    您的流畅 API 映射应该如下所示

    public class NoiseModelContext : DbContext
    {
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
    
            modelBuilder.Entity<Car>().Map(p => p.Requires("Type").HasValue("Car"));
            modelBuilder.Entity<Plane>().Map(p => p.Requires("Type").HasValue("Plane"));
        }
    
        public DbSet<NoiseOrigin> NoiseOrigins { get; set; }
    
        public DbSet<NoiseRecord> NoiseRecords { get; set; }
    }
    

    要获取所有汽车噪音记录,您的查询将如下所示

    using (var db = new NoiseModelContext()) {
        var records = db.NoiseRecords.Where(p => p.Origin is Car);
        // or like this - the result is the same.
        var records2 = db.NoiseOrigins.OfType<Car>().SelectMany(p => p.NoiseRecords);
    }
    

    【讨论】:

    • 非常感谢您的帮助,我真的很感激。您的解决方案的问题是我的目标是自动“预加载”导航属性。我想避免手动填充我的 Cars/Plane 的 NoiseRecords 属性。因此,实际上我对您的解决方案有些不理解,如果您必须使用 Datacontext 请求获取记录,那么映射的意义何在?如果我必须写一个额外的请求,那么我就会把抽象类扔掉,因为我没有用它赢得任何东西。
    • 在实体框架中,流式 API 只能用于定义您的概念模型如何映射到您的数据库。无法自动预加载导航属性。您可以使用 LazyLoading 按需加载导航属性,也可以使用即时加载将导航属性的值包含在查询中。 var 结果 = db.NoiseOrigins.OfType().Include(p => p.NoiseRecords)
    • 使用抽象基类 NoiseOrigin,您可以让您的模型使用 TablePerHierarchy 继承映射将 Plane 和 Car 持久保存在同一个数据库表中。但更重要的是,与接口相比,您可以使用基类作为导航属性。线 modelBuilder.Entity().Map(p => p.Requires("Type").HasValue("Car"));只是意味着类 Car 映射到与基类 NoiseOrigin 相同的表,但需要列 Type 来保存字符串值“Car”,以便将其标识为 Car 类型的对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多