LINQ到SQL的分离和数据结构的可重用性
本文关键字:数据结构 SQL 分离 LINQ | 更新日期: 2023-09-27 18:13:35
这是我的表的简化SQL,转换为LINQ to SQL模型。
CREATE TABLE Campaign (
Id int PRIMARY KEY,
Name varchar NOT NULL
);
CREATE TABLE Contract (
Id int PRIMARY KEY,
CampaignId int NULL REFERENCES Campaign(Id)
);
现在我有这样的类(这些是在不同的命名空间中,而不是来自数据模型的实体类)。
public class CampaignInfo {
public static CampaignModel Get(DataModel.CampaignInfo campaign) {
return new CampaignInfo {
Id = campaign.Id,
Name = campaign.Name,
Status = CampaignStatus.Get( c )
};
}
public int Id {get; set;}
public int Name {get; set;}
public CampaignStatus { get; set;}
}
public class CampaignStatus {
public static CampaignStatus Get(DataModel.Campaign campaign) {
return new CampaignStatus {
Campaign = campaign.Id, // this is just for lookup on client side
ContractCount = campaign.Contracts.Count()
// There is much more fields concerning status of campaign
};
}
public int Campaign { get; set; }
public int ContractCount {get; set;}
}
然后我运行query:
dataContext.Campaigns.Select( c => CampaignInfo.Get( c ) );
另一段代码可以这样做:
dataContext.Campaigns.Where( c => c.Name == "DoIt" ).Select( c => CampaignInfo.Get( c ) );
或者我想获得活动的状态列表:
dataContext.Campaigns.Select( c => CampaignStatus.Get( c ) );
注意:这些调用的结果被转换为JSON,因此不需要跟踪原始数据库实体。
可以看到,有两个目标。控制从数据库中获取的数据,并在其他地方重用这些结构。然而,这种方法是一个巨大的错误,因为类返回对象并在表达式树中使用它。
现在我明白了,它不能神奇地创建表达式,使整个事情与一个查询。相反,它是为每个竞选活动分别计算的。在相当复杂的情况下,它是丑陋的减速。
是否有一些简单的方法来实现这一点?我猜,这些类应该返回一些表达式,但我是完全新的这个领域,我不知道该怎么做。
一般的问题,如果我理解正确的话,是您有一些业务逻辑,您不希望在整个代码中重复(DRY)。你希望能够在你的LINQ方法中使用这个逻辑。
LINQ(表达式树)的一般解决方案是创建一个过滤器或转换函数,返回一个IQueryable
,这样你就可以在查询发送到数据库之前对它进行进一步的处理。
这里有一个方法:
// Reusable method that returns a query of CampaignStatus objects
public static IQueryable<CampaignStatus>
GetCampaignStatusses(this IQueryable<Compaign> campaigns)
{
return
from campaign in campaigns
new CampaignStatus
{
Campaign = campaign.Id,
ContractCount = compaign.Contracts.Count()
};
}
设置好后,可以编写以下代码:
using (var db = new DataModel.ModelDataContext() )
{
return
from campaign in db.Campaigns.WithContractCount()
from status in db.Campaigns.GetCampaignStatusses()
where campaign.Id == status.Campaign
select new
{
Id = campaign.Id,
Name = campaign.Name,
Status = status
};
}
有一个返回IQueryable
的方法允许你做各种额外的操作,而不需要那个方法知道它。例如,您可以添加过滤:
from campaign in db.Campaigns.WithContractCount()
from status in db.Campaigns.GetCampaignStatusses()
where campaign.Id == status.Campaign
where campaign .Name == "DoIt"
where status .ContractsCount < 10
select new
{
Id = campaign.Id,
Name = campaign.Name,
Status = status
};
或在输出中添加额外的属性:
from campaign in db.Campaigns.WithContractCount()
from status in db.Campaigns.GetCampaignStatusses()
where campaign.Id == status.Campaign
select new
{
OtherProp = campaign.OtherProp,
Id = status.Campaign,
Name = campaign.Name,
Status = status
};
这将被转换成一个高效的SQL查询。查询将不会从数据库中获得超过严格需要的记录或列。
你可以这样写:
using( var dataContext = new DataModel.ModelDataContext() )
{
dataContext.Campaigns.Select( c => new {
Id = c.Id,
Name = c.Name,
Status = new CampaignStatus()
{
ContractCount = c.Contracts.Count()
}
})
}