C# 通过LINQ加载基于抽象父属性的具体子类型

C# 通过LINQ加载基于抽象父属性的具体子类型,c#,linq,entity-framework,wcf-data-services,odata,C#,Linq,Entity Framework,Wcf Data Services,Odata,我刚刚移动到的项目有一个抽象类Product,之所以选择这样做,是因为有4个子类型被认为是一个产品,并且具有相当多的通用性(合成的原因)产品具有与其关联的产品类型枚举。我需要创建一些与Product相关的静态功能,比如GetAllProducts() 这就是我的问题所在,因为Product表只有公共性数据,我需要每个ProductType点击并选择与Product表关联的自己的表信息 模型的后端使用EntityFramework+OData,这是一种我不熟悉的技术 从数据库中获取每个子类型的完全

我刚刚移动到的项目有一个抽象类
Product
,之所以选择这样做,是因为有4个子类型被认为是一个产品,并且具有相当多的通用性(合成的原因)<代码>产品具有与其关联的
产品类型
枚举。我需要创建一些与
Product
相关的静态功能,比如
GetAllProducts()

这就是我的问题所在,因为
Product
表只有公共性数据,我需要每个
ProductType
点击并选择与
Product
表关联的自己的表信息

模型的后端使用EntityFramework+OData,这是一种我不熟悉的技术

从数据库中获取每个子类型的完全加载数据(+与之相关的所有公共性)的适当方法是什么,即使在我从linq查询中选择该子类型之前,我不知道该子类型是什么?假设我返回了数据,打开
ProductType
通过它们自己的构造函数创建实际的子类型有意义吗?

var result=(
            var result=(
                        from product in context.Products
                        join child1 in context.Child1s
                        on product.ID equals child1.ProductID
                        join child2 in context.Child2s
                        on product.ID equals child2.ProductID
                        join child3 in context.Child3s
                        on product.ID equals child3.ProductID
                        join child4 in context.Child4s
                        on product.ID equals child4.ProductID
                        where product.ID<1000
                        select new {

                                        AnonTypeProduct=product,
                                        AnonTypeChild1=child1,
                                        AnonTypeChild2=child2,
                                        AnonTypeChild3=child3,
                                        AnonTypeChild4=child4,

                        }).ToList();
        IEnumerable<Child1> ch1list=new IEnumerable<Child1>();
        IEnumerable<Child2> ch2list =new IEnumerable<Child2>();
        IEnumerable<Child3> ch3list=new IEnumerable<Child3>();
        IEnumerable<Child4> ch4list=new IEnumerable<Child4>();
        foreach(var result in results)
        {
            Child1 ch1=new Child1();
            ch1=result.AnonTypeChild1;
            ch1.Product=AnonTypeProduct;
            Child2 ch2=new Child2();
            ch2=result.AnonTypeChild2;
            ch2.Product=AnonTypeProduct;
            Child3 ch3=new Child3();
            ch3=result.AnonTypeChild3;
            ch3.Product=AnonTypeProduct;
            Child1 ch4=new Child4();
            ch4=result.AnonTypeChild4;
            ch4.Product=AnonTypeProduct;
            ch1list.Add(ch1);
            ch1list.Add(ch2);
            ch1list.Add(ch3);
            ch1list.Add(ch4);
        }
从上下文中的产品 在context.Child1s中加入child1 在product.ID上等于child1.ProductID 在context.Child2s中加入child2 在product.ID上等于child2.ProductID 在context.Child3s中加入child3 在product.ID上等于child3.ProductID 在上下文中加入child4.Child4s 在product.ID上等于child4.ProductID
product.ID关于EF+WCF数据服务(OData是协议,WCF DS是OData的Microsoft实现)最酷的部分是,这其中很多都是魔术。你不需要任何特殊的连接或其他魔术

这里有一些代码可以帮助您开始:(我保证,我会在下面详细介绍。)

使用系统;
使用System.Data.Entity;
使用系统、数据、服务;
使用System.Data.Services.Common;
使用System.ServiceModel;
名称空间Scratch.Web
{
// 4
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
// 1
公共类服务:数据服务
{
静态ScratchService()
{
// 2
SetInitializer(新的ScratchContextInitializer());
}
公共静态void InitializeService(DataServiceConfiguration配置)
{
// 3
config.SetEntitySetAccessRule(“*”,EntitySetRights.All);
config.SetServiceOperationAccessRule(“*”,ServiceOperationRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion=DataServiceProtocolVersion.V3;
// 4
config.UseVerboseErrors=true;
}
}
公共类ScratchContextInitializer:DropCreateDatabaseIfModelChanges
{
受保护的覆盖无效种子(ScratchContext上下文)
{
种子(上下文);
// 5
context.Products.Add(新产品)
{
Name=“DP1”,
DiscontractDAT=DateTime.Now.AddDays(-7)
});
context.Products.Add(新折扣产品)
{
Name=“DP1”,
折扣=3.14
});
}
}
// 6
公共类ScratchContext:DbContext
{
公共数据库集产品{get;set;}
}
// 7
公共抽象类产品
{
公共int ID{get;set;}
公共字符串名称{get;set;}
}
// 7
公共类折扣产品:产品
{
公共双折扣{get;set;}
}
// 7
公共类产品:产品
{
公共日期时间终止日期{get;set;}
}
}
快速演练:

  • 1:
    ScratchService
    是本例中的WCF数据服务。它继承自
    DataService
    ,并提供一个
    DbContext
    (EF概念)作为泛型类型
  • 2:我们使用静态构造函数来设置数据库初始值设定项,因为我一直在修改这段代码
  • 3:我们使实体集和服务操作对服务消费者可见(不建议采用
    */All
    方法)
  • 4:我们启用调试(始终有用)
  • 5:我们在数据库中植入种子,以获取一些数据
  • 6:我们为EF创建了一个
    DbContext
    ,并将抽象类
    产品
    公开为
    DbSet
    (请注意,您需要WCF DS 5或更高版本才能与
    DbContext
    ;WCF DS 5.0.1[或5.1.0-rc1,如果您勇敢的话]和EF 4.3.1配合使用。)
  • 7:我们创建了一个类结构,根上有一个抽象类和两个派生类
请注意,当EF起作用时,您将遵循其规则: -如果没有
DataServiceKey
属性,我就可以拥有
ProductId
,EF将使该键成为实体的键,WCF DS将尊重该键 -TPT/TPH/TPC均为每EF设置 -如果您想首先从数据库中编写代码(听起来您可能会这么做),那么有一个

using System;
using System.Data.Entity;
using System.Data.Services;
using System.Data.Services.Common;
using System.ServiceModel;

namespace Scratch.Web
{
    // 4
    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    // 1
    public class ScratchService : DataService<ScratchContext>
    {
        static ScratchService()
        {
            // 2
            Database.SetInitializer(new ScratchContextInitializer());
        }

        public static void InitializeService(DataServiceConfiguration config)
        {
            // 3
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
            // 4
            config.UseVerboseErrors = true;
        }
    }

    public class ScratchContextInitializer : DropCreateDatabaseIfModelChanges<ScratchContext>
    {
        protected override void Seed(ScratchContext context)
        {
            base.Seed(context);
            // 5
            context.Products.Add(new DiscontinuedProduct
                                     {
                                         Name = "DP1",
                                         DiscontinuedAt = DateTime.Now.AddDays(-7)
                                     });
            context.Products.Add(new DiscountedProduct
                                     {
                                         Name = "DP1",
                                         Discount = 3.14
                                     });
        }
    }
    // 6
    public class ScratchContext : DbContext
    {
        public DbSet<Product> Products { get; set; }
    }
    // 7
    public abstract class Product
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
    // 7
    public class DiscountedProduct : Product
    {
        public double Discount { get; set; }
    }
    // 7
    public class DiscontinuedProduct : Product
    {
        public DateTime DiscontinuedAt { get; set; }
    }
}