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

C# C如何将DbContext.Database.SqlQuery与抽象/派生类一起使用,c#,entity-framework,C#,Entity Framework,所以,我的情况是,我正在使用EF6和一个组件表,该表使用每个层次结构的表模式。我有一个抽象组件类和一些继承它的类,比如FirstNameComponent 该呼叫看起来如下所示: var sql = "Select * from Components"; var components = DbContext.Database.SqlQuery<Component>(sql).ToList(); 在这种情况下,我必须在DbContext或DbSet之外使用SqlQuery 正如您所期

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

该呼叫看起来如下所示:

var sql = "Select * from Components";
var components = DbContext.Database.SqlQuery<Component>(sql).ToList();
在这种情况下,我必须在DbContext或DbSet之外使用SqlQuery

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


有没有一种方法可以使用自定义模型绑定器或表上带有鉴别器列的东西来告诉SqlQuery调用每个组件使用哪些类?或者可以采用另一种方式将行序列化/反序列化到组件类中?

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

比方说,组件类是一个抽象类,FirstNameComponent继承了这个抽象类

因此,您希望您的组件类看起来像-

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))
    }
}
更新

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

一旦你拥有了所有的组件,你就可以在ComponentType字段中使用一个简单的Where子句过滤掉所需的类型-


因此,在本例中,我需要使用SqlQuery off DbContext.Database或DbSet,因为我需要使用自定义sql来获取组件。你能提供一个能同时使用你所设计的映射和SqlQuery的解决方案吗?@KevDev424-看看我更新的答案…正如我所提到的,你可以编写一个更动态的程序,在运行时解析组件的类型…看起来不错,但是,如果我在进行查询时不知道类型,并且希望像默认情况下那样依赖上下文映射,该怎么办?我希望使用自定义sql获取所有组件,并使抽象到具体的组件映射自动工作。我可能要求的太多了。嗯……我明白你的意思……但是因为你不能实例化一个抽象类,所以没有一种直接的方法可以一次获得所有组件,然后转换为派生类型。这就给你留下了两个选择,不过还有更多的选择更改方法,以便在查询需要强制转换到的派生类型或使用automapper(例如,他们没有使用SqlQuery)之前知道,我将以此作为答案,因为我认为这是我能做的最接近的事情。不过,我改变了方法,对组件ID进行了一次自定义查询,然后使用DbSet和带有ID的where子句进行第二次查询,以获得每个派生类的自定义映射。我认为在一个自定义查询中没有一个好方法可以做到这一点。
var components = ComponentContext.Components.OfType<FirstNameComponent>();
var components = ComponentContext.Components.Where(c => c is FirstNameComponent).ToList();
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);
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>();
var firstNameComponents = components.Where(c => c.ComponentType == nameof(FirstNameComponent)).ToList();