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,因此不需要跟踪原始数据库实体。

可以看到,有两个目标。控制从数据库中获取的数据,并在其他地方重用这些结构。然而,这种方法是一个巨大的错误,因为类返回对象并在表达式树中使用它。

现在我明白了,它不能神奇地创建表达式,使整个事情与一个查询。相反,它是为每个竞选活动分别计算的。在相当复杂的情况下,它是丑陋的减速。

是否有一些简单的方法来实现这一点?我猜,这些类应该返回一些表达式,但我是完全新的这个领域,我不知道该怎么做。

LINQ到SQL的分离和数据结构的可重用性

一般的问题,如果我理解正确的话,是您有一些业务逻辑,您不希望在整个代码中重复(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()  
            }  
        })  
}