2012-03-16 90 views
0

我的网站有大量的小部件,我想在此基础上传入的URL过滤他们说一个Widget具有以下结构:过滤逗号分隔数据

public class Widget { 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Urls { get; set; } 
} 

其中的url是逗号分隔的列表应显示的插件的网址,如:

/,/博客/,/博客/ 123 /新闻/ *

新闻后的星号表示了Widget只要传入的网址以/ News /开头就会被选中。

我该如何修改以下方法来根据上述条件过滤窗口小部件?

public IList<Widget> GetWidgets(string url) { 
    return _session 
     .Where(w => w.Urls.Contains(url)) 
     .ToList(); 
} 

理想情况下,我想使用linq查询,它只能击中数据库一次。我会很感激帮助。谢谢

回答

1

我设法加入我自己的外卡赛发电机来解决这个问题。有关如何注册发生器的示例,请参阅http://sentinel101.wordpress.com/2010/12/30/extend-nhibernate-linq-for-regex-matching/。这里的发电机柜面有人有兴趣:

public class WildCardMatchGenerator : BaseHqlGeneratorForMethod { 
    public WildCardMatchGenerator() { 
     var methodDefinition = ReflectionHelper.GetMethodDefinition(() => WildCardMatchExtensions.WildCardMatch(null, null, ',')); 
     SupportedMethods = new[] { methodDefinition }; 
    } 

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) { 
     return treeBuilder.Equality(treeBuilder.MethodCall("[dbo].[WildCardMatch]", new[] { 
      visitor.Visit(arguments[0]).AsExpression(), 
      visitor.Visit(arguments[1]).AsExpression(), 
      visitor.Visit(arguments[2]).AsExpression() 
     }), treeBuilder.Constant(1)); 
    } 
} 

这里是WildCardMatch UDF:

CREATE FUNCTION [dbo].[WildCardMatch] (
    @Pattern NVARCHAR(MAX), 
    @Input NVARCHAR(MAX), 
    @Separator NVARCHAR(5) 
) 
RETURNS BIT 
AS 
BEGIN 
    SET @Pattern = REPLACE(@Pattern, '*', '%') 

    DECLARE @RtnValue BIT 
    SELECT @RtnValue = CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END FROM [dbo].[Split](@Pattern, @Separator) WHERE @Input LIKE [Data] 

    RETURN @RtnValue 
END 

并调用Split函数(从http://blogs.microsoft.co.il/blogs/itai/archive/2009/02/01/t-sql-split-function.aspx):

CREATE FUNCTION [dbo].[Split] 
( 
    @RowData NVARCHAR(MAX), 
    @Separator NVARCHAR(MAX) 
) 
RETURNS @RtnValue TABLE 
(
    [Id] INT IDENTITY(1,1), 
    [Data] NVARCHAR(MAX) 
) 
AS 
BEGIN 
    DECLARE @Iterator INT 
    SET @Iterator = 1 

    DECLARE @FoundIndex INT 
    SET @FoundIndex = CHARINDEX(@Separator, @RowData) 

    WHILE (@FoundIndex > 0) 
    BEGIN 
     INSERT INTO @RtnValue ([Data]) 
     SELECT Data = LTRIM(RTRIM(SUBSTRING(@RowData, 1, @FoundIndex - 1))) 

     SET @RowData = SUBSTRING(@RowData, @FoundIndex + DATALENGTH(@Separator)/2, LEN(@RowData)) 
     SET @Iterator = @Iterator + 1 
     SET @FoundIndex = CHARINDEX(@Separator, @RowData) 
    END 

    INSERT INTO @RtnValue ([Data]) 
    SELECT Data = LTRIM(RTRIM(@RowData)) 

    RETURN 
END 

最后你”需要C#实现上述UDF:

public static class WildCardMatchExtensions { 
    public static bool WildCardMatch(this string pattern, string input, char separator = ',') { 
     foreach (var str in pattern.Split(new char[] { separator }, StringSplitOptions.RemoveEmptyEntries)) { 
      if (Regex.IsMatch(input, Regex.Escape(str.Trim()).Replace("\\*", ".*"))) 
       return true; 
     } 

     return false; 
    } 
} 

希望这会有所帮助。