C# 是的,这是可能的。这是明智的,它会使它更快,这是一个好的设计理念吗?根据您提供的信息,这些问题无法回答。@FlorianSchmidinger我的代码又大又复杂,而且是用巴西葡萄牙语编写的。我只是给出了转换为SP的逻辑。@Hogan我很肯定这会使我的应用程

C# 是的,这是可能的。这是明智的,它会使它更快,这是一个好的设计理念吗?根据您提供的信息,这些问题无法回答。@FlorianSchmidinger我的代码又大又复杂,而且是用巴西葡萄牙语编写的。我只是给出了转换为SP的逻辑。@Hogan我很肯定这会使我的应用程,c#,sql-server,loops,stored-procedures,C#,Sql Server,Loops,Stored Procedures,是的,这是可能的。这是明智的,它会使它更快,这是一个好的设计理念吗?根据您提供的信息,这些问题无法回答。@FlorianSchmidinger我的代码又大又复杂,而且是用巴西葡萄牙语编写的。我只是给出了转换为SP的逻辑。@Hogan我很肯定这会使我的应用程序更快。@EdgarSalazar-我对此表示怀疑。如果是这样的话,我预计您的应用程序服务器电源不足,或者您的C#代码实现不好。您描述的业务规则比SQL server更适合C#代码。但是正如我所说的,如果没有更多的细节,我真的说不出来除了这个非


是的,这是可能的。这是明智的,它会使它更快,这是一个好的设计理念吗?根据您提供的信息,这些问题无法回答。@FlorianSchmidinger我的代码又大又复杂,而且是用巴西葡萄牙语编写的。我只是给出了转换为SP的逻辑。@Hogan我很肯定这会使我的应用程序更快。@EdgarSalazar-我对此表示怀疑。如果是这样的话,我预计您的应用程序服务器电源不足,或者您的C#代码实现不好。您描述的业务规则比SQL server更适合C#代码。但是正如我所说的,如果没有更多的细节,我真的说不出来除了这个非常好的答案!懒惰和优化——OP应该有很大的改进。懒散的评估应该可以消除他高cpu使用率的问题。我看不出那种。。。也许这没关系。连接是IEnumerable的,所以我可以直接返回它。一旦您有了expandedRecords,您就可以按所需的属性进行订购。“你不能吗?”埃德加,我看了你的代码,意识到逻辑更复杂。然而,我认为这段代码是一个很好的起点。顺便说一句,我看到您有一些类似ExcludedDates的东西,您不应该使用Any扩展方法来查看是否有日期,而应该使用HashSet或similar来加快速度。递归CTE通常用于树遍历(它们可以适用于小树)。这不是一个树遍历,我认为它的性能很差。(除非您的DB服务器与您的应用程序服务器相比明显过剩或使用不足。)@Hogan它可以用来满足问题中要求的存储过程,我敢打赌它比当前的实现更快。
Id: 1
Name: Foo
Date: 03/10/2014
IsRepeatable: true
RepetitionType: 3 (Monthly)
RepeatingEndDate 05/10/2014
Id: 1
Name: Foo
Date: 03/10/2014
IsRepeatable: true
RepetitionType: 3 (Monthly)
RepeatingEndDate 05/10/2014


Id: 1
Name: Foo
Date: 04/10/2014
IsRepeatable: true
RepetitionType: 3 (Monthly)
RepeatingEndDate 05/10/2014


Id: 1
Name: Foo
Date: 05/10/2014
IsRepeatable: true
RepetitionType: 3 (Monthly)
RepeatingEndDate 05/10/2014
public class Record
{
    public int Id { get; set;} 
    public string Name {get; set;}

    public DateTime Date {get; set;}

    public bool IsRepeatable {get; set;}

    public int RepetitionType {get; set;}
    public DateTime? RepeatingEndDate { get; set; }
}
public static class RecordExtensions
{

    private static Func<DateTime, DateTime>[] PeriodIncrementers = new Func<DateTime, DateTime>[]
    {
        (date) => date, // RepetitionType = 0
        (date) => date.AddDays(1), // RepetitionType = 1 (daily)
        (date) => date.AddDays(7), // RepetitionType = 2 (weekly)
        (date) => date.AddMonths(1), // RepetitionType = 3 (monthy)
        (date) => date.AddMonths(3), // RepetitionType = 4 (quarterly)
        (date) => date.AddMonths(6), // RepetitionType = 5 (semiannually)
        (date) => date.AddYears(1), // RepetitionType = 6 (annually)
        (date) => date.AddYears(2), // RepetitionType = 7 (biannually)
    };

    private static Func<DateTime, DateTime>[] DefaultDateLimiters = new Func<DateTime, DateTime>[]
    {
        (date) => date, // RepetitionType = 0
        (date) => (new DateTime(date.Year, date.Month, 1)).AddMonths(1).AddDays(-1), // RepetitionType = 1 (daily). Limit: last day of month
        (date) => date.AddDays(7 * 10 ), // RepetitionType = 2 (weekly). Limit: 10 weeks
        (date) => date.AddYears(1), // RepetitionType = 3 (monthy). Limit: 1 year
        (date) => date.AddYears(2), // RepetitionType = 4 (quarterly). Limit:  2 year
        (date) => date.AddYears(4), // RepetitionType = 5 (semiannually). Limit: 4 years 
        (date) => date.AddYears(8), // RepetitionType = 6 (annually). Limit: 8 years
        (date) => date.AddYears(16), // RepetitionType = 7 (biannually). Limit: 16 years

    };

    public static IEnumerable<Record> ExpandRepetitions(this IEnumerable<Record> records, DateTime? fromDate, DateTime? toDate)
    {
        var concatenation = Enumerable.Empty<Record>();
        foreach (var record in records)
        {
            concatenation = concatenation.Concat(ExpandRepetition(record, fromDate, toDate));
        }
        return concatenation;
    }

    private static IEnumerable<Record> ExpandRepetition(Record record, DateTime? fromDate, DateTime? toDate)
    {
        if ((fromDate == null || fromDate.Value <= record.Date) && (toDate == null || toDate.Value >= record.Date))
        {
            yield return record;
        }
        var previousRecord = record;
        DateTime endDate = record.RepeatingEndDate == null ? DefaultDateLimiters[record.RepetitionType](record.Date) : record.RepeatingEndDate.Value;
        if (toDate.HasValue && toDate.Value < endDate) endDate = toDate.Value;

        var incrementer = PeriodIncrementers[record.RepetitionType];
        if (record.IsRepeatable)
        {
            DateTime date = incrementer(previousRecord.Date);
            while (date <= endDate )
            {
                if (fromDate == null || fromDate.Value <= date)
                {
                    var newRecord = new Record
                    {
                        Date = date,
                        IsRepeatable = previousRecord.IsRepeatable,
                        Name = previousRecord.Name,
                        RepeatingEndDate = previousRecord.RepeatingEndDate,
                        RepetitionType = previousRecord.RepetitionType
                    };
                    previousRecord = newRecord;
                    yield return newRecord;
                }
                date = incrementer(date);
            }
        }
    }
}
var records = new Record[] {
    new Record 
    {
        Id = 1,
        Date = DateTime.Today,
        IsRepeatable = false,
        Name = "Unique",
        RepetitionType = 0
    },
    new Record 
    {
        Id = 2,
        Date = DateTime.Today,
        IsRepeatable = true,
        Name = "Daily",
        RepetitionType = 1
    },
    new Record
    {
        Id = 3,
        Date = DateTime.Today,
        IsRepeatable = true,
        Name = "Weekly",
        RepetitionType = 2,
        RepeatingEndDate = DateTime.Today.AddDays(7*2)
    }
};

var allRecords = records.ExpandRepetitions(DateTime.Today.AddDays(7), new DateTime(2015, 3, 25)).ToList();
DECLARE @T TABLE(
    Id INT,
    Name VARCHAR(20),
    [Date] DATE,
    IsRepeatable BIT,
    RepetitionType TINYINT, --1=daily,2=weekly,3=monthly
    RepeatingEndDate DATE
)



INSERT INTO @T
    SELECT 1,'Foo','03/10/2014',1,3,'05/10/2014'

;WITH Date_CTE (Id,Name,IsRepeatable,RepetitionType,RepeatingEndDate,[Date])
AS
(
    select Id,Name,IsRepeatable,RepetitionType,RepeatingEndDate,[Date] from @T
    UNION ALL
    SELECT Id,Name,IsRepeatable,RepetitionType,RepeatingEndDate,
        CASE
            WHEN RepetitionType=1 THEN DATEADD(DAY,1,[Date])
            WHEN RepetitionType=2 THEN DATEADD(WEEK,1,[Date])
            WHEN RepetitionType=3 THEN DATEADD(MONTH,1,[Date])
        END [Date]
    FROM Date_CTE
    WHERE
        CASE
            WHEN RepetitionType=1 THEN DATEADD(DAY,1,[Date])
            WHEN RepetitionType=2 THEN DATEADD(WEEK,1,[Date])
            WHEN RepetitionType=3 THEN DATEADD(MONTH,1,[Date])
        END <= RepeatingEndDate
    AND IsRepeatable=1
)
select *
from Date_CTE