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; }
}
}