[英]Using LINQ-To-Entities to Generate Information
I am working on a website where a user can add tags to their posted books, much like is currently done for questions on Stack Overflow. 我正在一个网站上工作,在该网站上,用户可以将标签添加到已发布的书本上,就像目前针对Stack Overflow的问题所做的一样。
Classes : 课程 :
Books
{
bookId,
Title
}
Tags
{
Id
Tag
}
BooksTags
{
Id
BookId
TagId
}
Here are few sample records. 以下是一些示例记录。
Books
BookId Title
113421 A
113422 B
Tags
Id Tag
1 ASP
2 C#
3 CSS
4 VB
5 VB.NET
6 PHP
7 java
8 pascal
BooksTags
Id BookId TagId
1 113421 1
2 113421 2
3 113421 3
4 113421 4
5 113422 1
6 113422 4
7 113422 8
Questions 问题
I need to write something in LINQ to entity queries which gives me data according to the tags: 我需要在LINQ中为实体查询写一些东西,它根据标签为我提供数据:
Query : bookIds where tagid = 1
查询 :
bookIds where tagid = 1
Returns : bookid: 113421, 113422
返回 :
bookid: 113421, 113422
Query 2 : tags 1 and 2
查询2 :
tags 1 and 2
Returns : 113421
回报 :
113421
I need tags and their count to to show in related tags, so in first case my related tags class should have following result. 我需要标签及其计数才能显示在相关标签中,因此在第一种情况下,我的相关标签类应具有以下结果。
RelatedTags Tag Count 2 1 3 1 4 2 8 1 相关标签标签计数2 1 3 1 4 2 8 1
Second Case : 第二种情况 :
RelatedTags
Tag Count
3 1
4 1
How do I do this in LINQ? 如何在LINQ中做到这一点?
Just do Foreign keys mapping the tables in 1:N or 1:1 relations, and let the designer create navigation properties for you. 只需执行以1:N或1:1关系映射表的外键,然后让设计者为您创建导航属性。 (Books:BooksTags maps 1:N from Books.BookID to BooksTags.BookID, and BooksTags.TagID maps 1:1 to Tags.TagID).
(Books:BooksTags将1:N从Books.BookID映射到BooksTags.BookID,而BooksTags.TagID则将1:1映射到Tag.TagID)。 This is actually a disguised N:M relation.
这实际上是伪装的N:M关系。 I don't know if the designer picks this up directly, but with some fiddling you can get the navigation properties right.
我不知道设计者是否直接选择了它,但是通过一些摆弄可以使导航属性正确。
Now for the questions: 现在开始提问:
model.Tags.Where(t => t.ID == 1).Books.Select(b => b.ID)
Get all the tags present for a book, and join that table on the BooksTags, by this you can simply use Count() to get the count. 获取一本书的所有标签,然后将该表连接到BooksTags上,这样您就可以简单地使用Count()来获取计数。
On the first part, the interesting restriction is that the book has to match every tag entered, so a where clause of "where tagid == someId" wouldn't really work. 在第一部分,有趣的限制是,该书必须匹配输入的每个标签,因此“ where tagid == someId”的where子句实际上不会起作用。 I envision something like this (LINQ-to-objects example)
我设想这样的事情(LINQ到对象的示例)
List<int> selectedTagIds = new List<int>() { 1, 2 };
var query = from book in books
join booktag in booktags
on book.Id equals booktag.BookId
join selectedId in selectedTagIds
on booktag.TagId equals selectedId
group book by book into bookgroup
where bookgroup.Count() == selectedTagIds.Count
select bookgroup.Key;
Which basically performs a join from books to booktags and also to the list of selected tag ids and restricts the selection to where the count of book->tag matches equals the count of selected tag ids. 它基本上执行从书籍到书签的连接,也执行到选定标签ID列表的连接,并将选择范围限制为book-> tag匹配的数目等于选定标签ID的数目。
To pull the related tags, maybe something like this 要拉相关标签,也许像这样
var relatedTags = from book in query // use original query as base
join booktag in booktags
on book.Id equals booktag.BookId
join tag in tags
on booktag.TagId equals tag.Id
where !selectedTagIds.Contains(tag.Id) // exclude selected tags from related tags
group tag by tag into taggroup
select new
{
Tag = taggroup.Key,
Count = taggroup.Count()
};
Full code for the quick example. 快速示例的完整代码。 Not fully OOP, but you get the idea.
并不是完全面向对象的,但是您知道了。
using System;
using System.Collections.Generic;
using System.Linq;
namespace StackOverflow
{
class Program
{
static void Main()
{
List<Book> books = new List<Book>()
{
new Book() { Id = 113421, Title = "A" },
new Book() { Id = 113422, Title = "B" }
};
List<Tag> tags = new List<Tag>()
{
new Tag() { Id = 1, Name = "ASP" },
new Tag() { Id = 2, Name = "C#" },
new Tag() { Id = 3, Name = "CSS" },
new Tag() { Id = 4, Name = "VB" },
new Tag() { Id = 5, Name = "VB.NET" },
new Tag() { Id = 6, Name = "PHP" },
new Tag() { Id = 7, Name = "Java" },
new Tag() { Id = 8, Name = "Pascal" }
};
List<BookTag> booktags = new List<BookTag>()
{
new BookTag() { Id = 1, BookId = 113421, TagId = 1 },
new BookTag() { Id = 2, BookId = 113421, TagId = 2 },
new BookTag() { Id = 3, BookId = 113421, TagId = 3 },
new BookTag() { Id = 4, BookId = 113421, TagId = 4 },
new BookTag() { Id = 5, BookId = 113422, TagId = 1 },
new BookTag() { Id = 6, BookId = 113422, TagId = 4 },
new BookTag() { Id = 7, BookId = 113422, TagId = 8 }
};
List<int> selectedTagIds = new List<int>() { 1,2 };
// get applicable books based on selected tags
var query = from book in books
join booktag in booktags
on book.Id equals booktag.BookId
join selectedId in selectedTagIds
on booktag.TagId equals selectedId
group book by book into bookgroup
where bookgroup.Count() == selectedTagIds.Count
select bookgroup.Key;
foreach (Book book in query)
{
Console.WriteLine("{0}\t{1}",
book.Id,
book.Title);
}
// get related tags for selected tags
var relatedTags = from book in query // use original query as base
join booktag in booktags
on book.Id equals booktag.BookId
join tag in tags
on booktag.TagId equals tag.Id
where !selectedTagIds.Contains(tag.Id) // exclude selected tags from related tags
group tag by tag into taggroup
select new
{
Tag = taggroup.Key,
Count = taggroup.Count()
};
foreach (var relatedTag in relatedTags)
{
Console.WriteLine("{0}\t{1}\t{2}",
relatedTag.Tag.Id,
relatedTag.Tag.Name,
relatedTag.Count);
}
Console.Read();
}
}
class Book
{
public int Id { get; set; }
public string Title { get; set; }
}
class Tag
{
public int Id { get; set; }
public string Name { get; set; }
}
class BookTag
{
public int Id { get; set; }
public int BookId { get; set; }
public int TagId { get; set; }
}
}
So for selected tags 1 & 2, you'll get book A, and the related tags would be 3 (CSS) and 4 (VB). 因此,对于选定的标签1和2,您将获得书籍A,而相关的标签将是3(CSS)和4(VB)。
这与答案本身没有直接关系,但是您可能想看看linqpad,因为它可以帮助您直接从数据库中构建L2S语句。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.