C#如何将DbContext.Database.SqlQuery与抽象/派生类一起使用

时间:2017-04-06 00:11:10

标签: c# entity-framework

所以,我的情况是我使用EF6和Component表使用每个层次结构模式的表。我有一个抽象的Component类和一些继承它的类,比如FirstNameComponent。

电话看起来像这样:

var sql = "Select * from Components";
var components = DbContext.Database.SqlQuery<Component>(sql).ToList();

在这种情况下,我必须SqlQueryDbContext使用DbSet

正如您所期望的那样,这会查询表中的所有组件并尝试将它们映射到Component类,但由于它是抽象的,因此会抛出异常。

有没有办法使用自定义模型绑定器或表中的discriminator列来告诉SqlQuery调用哪些类用于每个组件?或者可能采用不同的方式将行序列化/反序列化为Component类?

1 个答案:

答案 0 :(得分:0)

您可以在抽象类中定义一个鉴别器属性(基本上是您想要作为鉴别器的列的名称,作为字符串)

说,您将Component类作为抽象类,FirstNameComponent继承该类。

所以,你希望你的Component课看起来像 -

public abstract class Component
{
    public const string Discriminator = "ComponentType";

    // Other properties/methods
}

现在,您的FirstNameComponent课程看起来像 -

public class FirstNameComponent : Component
{
    public const string TypeOfComponent = nameof(FirstNameComponent);

    public override string ComponentType // your discriminator column
    {
        get
        {
            return TypeOfComponent;
        }
    }
    // Other properties/methods
}

并在您的上下文中使用Fluent API构建模型时使用此属性。

public class ComponentContext: DbContext
{
    public DbSet<FirstNameComponent> FirstNameComponents { get; set; }

    // Other mappings 

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Component>()
            .Map<FirstNameComponent>(
                configuration =>
                configuration.Requires(Component.Discriminator).HasValue(FirstNameComponent.TypeOfComponent))
    }
}

因此,您的查询将类似于 -

var components = ComponentContext.Components.OfType<FirstNameComponent>();

甚至 -

var components = ComponentContext.Components.Where(c => c is FirstNameComponent).ToList();

<强>更新

查看更新后的问题,以下是如何重新构建查询以获取特定类型的Component -

string sqlQuery = @"Select * from Components Where ComponentType = @componentType";
string componentType = nameof(FirstNameComponent); //Can be made more dynamic

// Pass the type of component you need to cast to as a parameter
SqlParameter parameter = new SqlParameter("@componentType", componentType);

var components = DbContext.Database.SqlQuery<FirstNameComponent>(sqlQuery, parameter);

这应该会给你想要的结果。

更新2

所以,在对此进行了一些研究之后,我找到了this博客,其中讨论了使用Linq to Entities和EntitySQL的多态查询。

根据参考资料,您可以尝试另外一种方法来获取所有Components -

string sqlQuery = @"SELECT VALUE c FROM Components AS c";
System.Data.Entity.Core.Objects.ObjectContext objectContext = ((IObjectContextAdapter)ComponentContext).ObjectContext;
System.Data.Entity.Core.Objects.ObjectQuery<Component> objectQuery = objectContext.CreateQuery<Component>(sqlQuery);
List<Component> components = objectQuery.ToList<Component>();

如果您拥有所有Components,则可以使用Where字段上的简单ComponentType子句过滤掉所需的类型 -

var firstNameComponents = components.Where(c => c.ComponentType == nameof(FirstNameComponent)).ToList();