根据上下文将 DbFunctions 切换到非数据库实现
Switch DbFunctions to a non-db implementation depending on context
我有一个表达式使用 DbFunctions
class 来计算日期。它适用于 linq-to-entities
但我想将此表达式重新用于非数据库功能。是否可以检测是否在数据库上下文中评估表达式并使用相应的实现?我已经看到涉及模拟对象的单元测试解决方案,但我需要在通用业务逻辑中使用此表达式,因此模拟看起来不是一个好的解决方案。
这是我的表达:
public static Expression<Func<Transaction, bool>> Expired(int expirationPeriod)
{
return s => s.Status == Status.Created && DbFunctions.AddMinutes(s.UpdateDateUTC, expirationPeriod) < DateTime.UtcNow;
}
我希望能够做这样的事情:
public static Expression<Func<Transaction, bool>> Expired(int expirationPeriod)
{
return s => s.Status == Status.Created && MyCustomResolver.AddMinutes(s.UpdateDateUTC, expirationPeriod) < DateTime.UtcNow;
}
其中 MyCustomResolver
将根据上下文使用 DbFunctions
或 DateTime
实现。
interface ICustomResolver
{
DateTime AddMinutes(DateTime, int);
}
public class DbCustomResolver : ICustomResolver
{
public DateTime AddMinutes(DateTime time, int minutes)
{
return DbFunctions.AddMinutes(time, minutes);
}
}
public class NonDbCustomResolver : ICustomResolver
{
public DateTime AddMinutes(DateTime time, int minutes)
{
return time.AddMinutes(minutes);
}
}
ICustomResolver MyCustomResolver =
amIUsingDB ? new DbCustomResolver() : new NonDbCustomResolver();
现在,我想人们可以在 AddMinutes
中即时做出决定,但为什么呢? if()
最好只做一次,而不是每次都做。
最后我采用了以下方法:
定义一个带有 DbFunction
属性的函数。这样,如果在 Linq-to-Entities 表达式中使用,它会使用相应的 SQL 函数;如果在非数据库上下文中执行,它会使用 C# 函数
/// <summary>
/// Utilize functions for both Linq-to-Entities and non-db context
/// </summary>
public static class MyCustomResolver
{
[DbFunction("Edm", "AddMinutes")]
public static DateTime? AddMinutes(DateTime? timeValue, int addValue)
{
return timeValue?.AddMinutes(addValue);
}
}
使用上面定义的辅助函数构建表达式
public static Expression<Func<Transaction, bool>> Expired(int expirationPeriod)
{
return s => s.Status == Status.Created && MyCustomResolver.AddMinutes(s.UpdateDateUTC, expirationPeriod) < DateTime.UtcNow;
}
我有一个表达式使用 DbFunctions
class 来计算日期。它适用于 linq-to-entities
但我想将此表达式重新用于非数据库功能。是否可以检测是否在数据库上下文中评估表达式并使用相应的实现?我已经看到涉及模拟对象的单元测试解决方案,但我需要在通用业务逻辑中使用此表达式,因此模拟看起来不是一个好的解决方案。
这是我的表达:
public static Expression<Func<Transaction, bool>> Expired(int expirationPeriod)
{
return s => s.Status == Status.Created && DbFunctions.AddMinutes(s.UpdateDateUTC, expirationPeriod) < DateTime.UtcNow;
}
我希望能够做这样的事情:
public static Expression<Func<Transaction, bool>> Expired(int expirationPeriod)
{
return s => s.Status == Status.Created && MyCustomResolver.AddMinutes(s.UpdateDateUTC, expirationPeriod) < DateTime.UtcNow;
}
其中 MyCustomResolver
将根据上下文使用 DbFunctions
或 DateTime
实现。
interface ICustomResolver
{
DateTime AddMinutes(DateTime, int);
}
public class DbCustomResolver : ICustomResolver
{
public DateTime AddMinutes(DateTime time, int minutes)
{
return DbFunctions.AddMinutes(time, minutes);
}
}
public class NonDbCustomResolver : ICustomResolver
{
public DateTime AddMinutes(DateTime time, int minutes)
{
return time.AddMinutes(minutes);
}
}
ICustomResolver MyCustomResolver =
amIUsingDB ? new DbCustomResolver() : new NonDbCustomResolver();
现在,我想人们可以在 AddMinutes
中即时做出决定,但为什么呢? if()
最好只做一次,而不是每次都做。
最后我采用了以下方法:
定义一个带有
DbFunction
属性的函数。这样,如果在 Linq-to-Entities 表达式中使用,它会使用相应的 SQL 函数;如果在非数据库上下文中执行,它会使用 C# 函数/// <summary> /// Utilize functions for both Linq-to-Entities and non-db context /// </summary> public static class MyCustomResolver { [DbFunction("Edm", "AddMinutes")] public static DateTime? AddMinutes(DateTime? timeValue, int addValue) { return timeValue?.AddMinutes(addValue); } }
使用上面定义的辅助函数构建表达式
public static Expression<Func<Transaction, bool>> Expired(int expirationPeriod) { return s => s.Status == Status.Created && MyCustomResolver.AddMinutes(s.UpdateDateUTC, expirationPeriod) < DateTime.UtcNow; }