如果表B在搜索中匹配

时间:2018-03-14 08:10:01

标签: c# linq entity-framework-6

我有两张桌子

CREATE TABLE RetailGroup(
Id             int IDENTITY(1,1), 
GroupName      nvarchar(50),   
)     

CREATE TABLE RetailStore(
Id             int IDENTITY(1,1), 
StoreName      nvarchar(100),     
RetailGroupId  int  
)             

RetailStore中的RetailGroupId引用RetailGroup ID。我正在尝试创建一个搜索功能,我可以搜索RetailGroup和RetailsS​​tores。如果我得到一个匹配的RetailStore,我想要返回该组,它与所有匹配的商店记录相关联。如果我得到一个匹配的组,我想要组记录,但没有零售商店。

我尝试按以下方式进行:

public List<RetailGroup> SearchGroupsAndStores(string value)
{
    return _context.RetailGroups.Where(group => group.GroupName.Contains(value)).Include(group => group.RetailStores.Where(store => store.StoreName.Contains(value))).ToList();
}

但这是错误的,因为不应该使用include来进行选择。

这是我的实体框架模型

public class RetailGroup
{
    [Key]
    public int Id { set; get; }

    [MaxLength(50)]
    public String GroupName { set; get; }

    //Relations
    public ICollection<RetailStore> RetailStores { set; get; }
}

这是商店的那个

public class RetailStore
{
    [Key]
    public int Id { get; set; }

    [MaxLength(100)]
    public string StoreName { get; set; }

    [ForeignKey("RetailGroup")]
    public int RetailGroupId { get; set; }

    //Relations
    public RetailGroup RetailGroup { get; set; }

    public ICollection<EGPLicense> Licenses { get; set; }
}

如何创建LINQ以获取我要查找的结果?

3 个答案:

答案 0 :(得分:1)

使用投影返回所需结果的查询并不难:

var dbQuery = _context.RetailGroups
    .Select(rg => new
    {
        Group = rg,
        Stores = rg.RetailStores.Where(rs => rs.StoreName.Contains(value))
    })
    .Where(r => r.Group.GroupName.Contains(value) || r.Stores.Any());

问题是您希望结果包含在实体类中,而EF6既不支持投影到实体类型也不支持过滤包含。

要克服这些限制,可以使用AsEnumerable()方法切换到LINQ to Objects上下文,此方法将有效地执行数据库查询,然后使用委托块从匿名类型中提取实体实例投影,将过滤后的集合绑定到它并返回它:

var result = dbQuery
    .AsEnumerable()
    .Select(r =>
    {
        r.Group.RetailStores = r.Stores.ToList();
        return r.Group;
    })
    .ToList();

答案 1 :(得分:0)

尝试使用OR条件过滤组名称和商店名称。

return _context.RetailGroups
    .Where(group => group.GroupName.Contains(value) || group.RetailStores.Any(store => store.StoreName.Contains(value)))
    .Include(group => group.RetailStores.Where(store => store.StoreName.Contains(value)))
    .ToList();

另一种选择是进行2次搜索,一次针对群组,另一种针对商店。这里的问题是从两个结果中创建一组独特的组。

List<RetailGroup> retailGroups = new List<RetailGroup>();

var groupSearchResults = _context.RetailGroups
    .Where(group => group.GroupName.Contains(value))
    .Include(group => group.RetailStores.Where(store => store.StoreName.Contains(value)))
    .ToList();

var storeSearchResults = _context.RetailStores
    .Where(store => store.StoreName.Contains(value))
    .Select(store => store.RetailGroup)
    .ToList();

retailGroups.AddRange(groupSearchResults);
retailGroups.AddRange(storeSearchResults); 

// Remove duplicates by ID
retailGroups = retailGroups
    .GroupBy(group => group.Id)
    .Select(group => group.First());

答案 2 :(得分:-1)

使用OR条件并在一个语句中进行搜索:

public List<RetailGroup> SearchGroupsAndStores(string value)
{
    return _context.RetailGroups
    .Where(rg => rg.GroupName.Contains(value) || rg.RetailStores.Any(rs => rs.StoreName.Contains(value)))
    .Include(rg => rg.RetailStores.Where(rs => rs.StoreName.Contains(value)).ToList())
    .ToList();
}

或者您可以拆分搜索,先查找RetailGroups,然后搜索RetailStores并返回RetailGroup

public List<RetailGroup> SearchGroupsAndStores(string value)
{
    List<RetailGroup> searchResults = new List<RetailGroup>();
    searchResults.AddRange(_context.RetailGroups.Where(rg => rg.GroupName.Contains(value)).ToList());
    searchResults.AddRange(_context.RetailStores.Where(rs => rs.StoreName.Contains(value)).Select(rs => rs.RetailGroup).ToList());
}