LINQ(Language Integrated Query)
LINQ语言集成查询是一组用于C#语言的扩展。它允许编写C#代码对数据集进行查询,比如查询内存中的对象或查询远程数据库的表。利用linq,程序员不必掌握数据库查询语句而是使用Linq就能完成相同的查询任务。而传统数据查询的弱点很多,比如执行简单查询也需要冗长的操作代码,查询语句是字符串格式,无法让编译器执行检查错误及早提示,查询不是强类型,查询参数容易写错,查询结果没有真正面向对象,每次查询取结果还得事先知道列名或列索引,不使用抽象工厂的前提下,查询语句是定死的,只能应用于一种数据库。 即使使用抽象工厂,代码量也巨大。 Enumerable类为IEnumerable<T>扩展了用于查询内存中的对象的linq查询方法。而Queryable为IQueryable <T>扩展了对远程数据源进行linq查询的方法。 而在System.Collections命名空间下的集合类虽然不能使用那些从IEnumerable<T>上扩展的方法,但可以通过调用非泛型集合的Cast<T>()将其转换为泛型集合,从而可以使用Enumerable类提供的扩展方法。
Lambda表达式
格式
Lambda表达式比函数有着更为简洁的语法格式。在某些情况下使用Lamnbda就可以替代函数,让代码变得更简洁易读。而定义Lambda表达式与定义函数其实差别不大,而且还做到了简化。
e => e.Name == "sam" 定义函数你得声明函数的权限修饰符、形态修饰符和参数列表、返回类型等,而Lambda就这么一段代码就做完了函数的工作 e:参数 =>:操作符,可描述执行后面的逻辑……操作符后面的则是单个表达式,也可以是语句块。即函数的方法体。 示例
//有{}代码块的称为语句Lambda,无{}代码块的称为Lambda表达式 (string e) => e.Name == "sam"; e => e.Name == "sam"; e => { return e.Name == "sam"; } (string e, string x)=>{ return e.Name == "sam" && e.Age = 32; } (e, x) => { return e.Name == "sam" && e.Age = 32; } ()=>Console.WriteLine(); Lambda与委托
Lambda就是一个匿名的函数,所以你可以将Lambda当成委托实例作为参数进行传递,如果要这样做,则你定义的Lambda表达式的签名和返回类型必须符合委托的签名和返回类型
static void ShowTime(Func<DateTime> d) { Console.WriteLine(d().ToString()); } static void Main(string[] args) { Func<DateTime> getDateTime = () => DateTime.Now; //将匹配Func<T>委托签名和返回类型的lambda表达式当做委托使用 ShowTime(getDateTime); }
LINQ延迟查询机制
LINQ查询操作符并不会立即执行,它总是在查询结果集真正被使用的时候才会开启查询。 而且每次只将迭代的当前项存入内存中处理,这就降低了内存占用率。那些需要一次性统计所有集合的操作符如:OrderBy、Reverse、ToList、ToArray、ToDictionary,它们都会破坏延迟查询,也即调用这些操作符则会立即开启查询。
int[] numbers = new int[] { 0, 1, 2, 100 }; var result = numbers.Where(n => n <= 2); foreach (var item in result) Console.WriteLine(item); for (int i = 0; i < 10; ++i) numbers[i] = -numbers[i]; foreach (var item in result) Console.WriteLine(item);
LINQ查询表达式
LINQ查询表达式类似于SQL查询语句,但个人不喜欢它的书写格式。它是由from、join group by等句子组成的LINQ查询表达式,而LINQ查询表达式与直接使用LINQ扩展方法执行查询在语法结构上是不一样的,我认为后者更易于阅读,所以此处略过。
LINQ操作符
几乎每个Linq操作符都接收一个委托实例(Lambda),操作符对集合进行迭代,每迭代一次会自动调用Lambda,根据lambda来返回结果集。
1.过滤
根据参数提供的lambda表达式指定的逻辑过滤集合中的元素,将计算的结果存入结果集返回。可以按条件、按索引、按开头或结尾、按唯一的单个项进行筛选。
Where ( lambda ) ElementAt( int index ) Single( [ lambda ] ) First( [ lambda ] ) Last( [ lambda ] ) 2.投影
根据参数提供的lambda表达式返回的项,将项存入结果集返回
Select( lambda ) int[] a = { 1, 2, 3 }; var s = a.Select(i => i > 2); foreach (var item in s) { Console.WriteLine(item); } public class Book { public string Title { get; set; } public double Price { get; set; } public List<Author> Authors { get; set; } } public class Author { public string Name { get; set; } } public class Programe { static void Main(string[] args) { List<Book> books = new List<Book> { new Book { Title="寂静的春天", Price=19.8, Authors = new List<Author> { new Author{ Name="sam" }, new Author{ Name="leo" } } }, new Book { Title="万有引力之虹", Price=20.7, Authors=new List<Author> { new Author{ Name="korn" }, new Author{ Name="Tim" } } }, new Book { Title="卡拉马佐夫兄弟", Price=30.5, Authors=new List<Author> { new Author{ Name="lily" }, new Author{ Name="lvis" } } } }; IEnumerable<string> titleList = books.Select(book => book.Title); foreach (var title in titleList) { Console.WriteLine(title); } IEnumerable<double> priceList = books.Select(book => book.Price); foreach (var price in priceList) { Console.WriteLine(price); } IEnumerable<Book> bookList = books.Select(book => book); foreach (var book in bookList) { Console.WriteLine($"{ book.Title}{ book.Price}"); } IEnumerable<List<Author>> authorListList = books.Select(book => book.Authors); foreach (var authorList in authorListList) { foreach (var author in authorList) { Console.WriteLine(author.Name); } } } } SelectMany ( lambda ) IEnumerable<Author> authorList = books.SelectMany(book => book.Authors); 3.去重
根据参数提供的lambda表达式返回的项对集合进行去重,将去重后的结果存入结果集返回
Distinct( [ IEqualityComparer < T > comparer ] ) Except( IEnumerable < T > second [ , IEqualityComparer < T > comparer ] ) Intersect( IEnumerable < T > second [ , IEqualityComparer < T > comparer ] ) Union( IEnumerable < T > second ) using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Text; using System.Web.UI; using System.IO; namespace Yin.General { public static class LinqHelper<T> { public static IEqualityComparer<T> CreateComparer<TV>(Func<T, TV> keySelector) { return new CommonEqualityComparer<TV>(keySelector); } public static IEqualityComparer<T> CreateComparer<TV>(Func<T, TV> keySelector, IEqualityComparer<TV> comparer) { return new CommonEqualityComparer<TV>(keySelector, comparer); } private class CommonEqualityComparer<TV> : IEqualityComparer<T> { private readonly IEqualityComparer<TV> _comparer; private readonly Func<T, TV> _keySelector; public CommonEqualityComparer(Func<T, TV> keySelector, IEqualityComparer<TV> comparer) { _keySelector = keySelector; _comparer = comparer; } public CommonEqualityComparer(Func<T, TV> keySelector) : this(keySelector, EqualityComparer<TV>.Default) { } public bool Equals(T x, T y) { return _comparer.Equals(_keySelector(x), _keySelector(y)); } public int GetHashCode(T obj) { return _comparer.GetHashCode(_keySelector(obj)); } } } } 相等性比较器 var records = Authors.Distinct(LinqHelper<Author>.CreateComparer<string>(a => a.FirstName)); 4.转换
ToArray( ) ToList( ) ToDictionary( ) public class Animal { public int Id { get; set; } public string Name { get; set; } } List<Animal> list = new List<Animal> { new Animal{ Id=1, Name="sam"}, new Animal{ Id=2, Name="leo"} }; Dictionary<int, Animal> dictionary = list.ToDictionary( animal => animal.Id ); //用元素的id作为哈希字典的键 Console.WriteLine(dictionary[1].Name ); Cast<T>() AsEnumerable( ) AsQueryable( ) 聚合
Sum() Count() Min() Max() Average() Aggregate() 6.排序
按lambda表达式返回的项进行排序
OrderBy( lambda [ , IComparer < T > comparer] ) OrderByDescending( lambda [ , IComparer < T > comparer] ) ThenBy( lambda [ , IComparer < T > comparer] ) ThenByDescending( lambda [ , IComparer < T > comparer] ) Reverse( lambda [ , IComparer < T > comparer] ) 7.分组
按lambda表达式返回的项进行分组
List<Book> list = new List<Book> { new Book{ Title="寂静的春天", Price=19.8, Type="社科"}, new Book{ Title="单向度的人", Price=19.8, Type="社科"}, new Book{ Title="历史研究", Price=10.8,Type="历史"}, new Book{ Title="卡拉马佐夫兄弟", Price=10.8,Type="小说"}, }; var query = list.GroupBy(book => book.Type); StringBuilder bs = new StringBuilder(); foreach (var group in query) { bs.Append("-----" + group.Key + "-----\r\n"); foreach (var book in group) { bs.Append(" " + book.Title + "\r\n"); } Console.WriteLine(bs.ToString()); bs.Clear(); } var query = list.GroupBy(book =>new { book.Type, book.Price }); StringBuilder bs = new StringBuilder(); foreach (var group in query) { bs.Append("-----" + group.Key.Type + "-----\r\n"); foreach (var book in group) { bs.Append(" " + book.Title + "\r\n"); } Console.WriteLine(bs.ToString()); bs.Clear(); } ToLookup(lambda ) var grouping = list.ToLookup(book => book.Type); foreach (var group in grouping) { Console.WriteLine($"========{group.Key}========"); foreach(var item in group) { Console.WriteLine(item.Title); } } 8.联结
将N张表(集合)建立联结,每张表都有一个共同的键,键相同的行数据则被归纳到一行中, 下表中的出版社和图书以出版社ID为关联键位,使用联结查询后,相同关联键位的行数据会被整合到一行中
操作符:Join ( ) | GroupJoin ( ) 9-1.内联结:查询关联的多张表,但不返回无关联的记录(inner join)
Join ( 联结的另一个集合,能返回被查询的左边集合的关联键位的函数,能返回被联结的右边集合的关联键位的函数,根据前两个函数的参数能创建新结果集的函数 )
var query = publishers.Join(books, publish => publish.ID, book => book.PublisherID, (publish, book) => new { pubID = publish.ID, pubName = publish.Name, bookName = book.Name }); 9-1.分组联结:将关联的多张表的记录进行分组
单表分组使用GroupBy,多表连接分组则使用GroupJoin
GroupJoin ( 联结的另一个集合,能返回被查询的左边集合的关联键位的函数,能返回被联结的右边集合的关联键位的函数,根据前两个函数的参数能创建新结果集的函数 )
var query = publishers.GroupJoin(books, p => p.ID, b => b.PublisherID, (publish, bookList) => new { pubID = publish.ID, pubName = publish.Name, bookAllName = !bookList.Any()==true?"无":string.Join(",",bookList.Select(b=>b.Name)) }); 9-2.外连接:键位不相等时,保证左边可以返回,右边则以null填充(left join)
使用GroupJoin 方法,利用投影和
var query = publishers.GroupJoin(books, p => p.ID, b => b.PublisherID, (publish, bookList) => new { publish.ID, publish.Name, bookList }). SelectMany(x => x.bookList.DefaultIfEmpty(), (publish, book) => new { pubID = publish.ID, pubName = publish.Name, bookName = book == null ? "无" : book.Name }); 左联结的表达式版本
var list = from b in books join p in publishers on b.PublisherID equals p.ID into newTable from x in newTable.DefaultIfEmpty( ) select new { ID = b.ID, Name = b.Name, pubName = x==null? "null":x.Name }; 大部分情况下可能会使用GroupJoin方法,但是假如关键键位本身是必填的,那么使用Join方法就可以了,因为关联键位是必填,则不会存在关联到空数据的情况,也就没必要使用GroupJoin。
10.全连接
在sql中存在全连接的概念,它是指两张或N张表无论左或右出现了未匹配上的行时,都以null填充。在linq中并不支持全连接,如果有这种需求,可以考虑先得到两个结果集,最后再UNION即可。
11.交叉连接
也称笛卡尔积查询,可使用linq表达式写个简单的例子:
List < char > aList = new List < char > { 'A' , 'B' , 'C' }; List < char > bList = new List < char > { 'x' , 'y' }; var query = from a in aList from b in bList select new { a , b }; foreach ( var item in query ) { Console . WriteLine ( $" { item . a } 与上 { item . b } " ); } 12.串联
将5另一个序列与当前序列合并为一个序列
13.分区
操作符:Skip ( ) | SkipWhile ( ) | Take ( ) | TakeWhile ( ) Skip():跳过集合中指定个数的项,返回剩下的项。
SkipWhile():返回满足条件的项。
Take():从索引起始位置开始提取指定个数的项。
TakeWhile():提取满足条件的项
14.生成
DefaultIfEmpty() :用于当集合为空时为集合提供带有默认值的一个项
15.判断
操作符:All ( ) | Any ( ) | Contains ( ) All() :集合中所有项都满足条件吗?
Any():集合至少包含了一个项吗?
Contains():集合包含了参数指定的项吗?
16.比较
逐一比较两个集合中的项是否相等,如果相等则两个集合被视为相等。 LINQ To Object
查询泛型集合
所有的LINQ操作符(即扩展方法)均定义在System.Linq.Enumerable静态类中,为所有实现了IEnumerable<T>的强类型集合扩展出了LINQ查询方法。所以数组、泛型集合都可以使用LINQ查询。
object[] objArray = { "sam", 32, "beijingStreet", false, 'a' }; var records = objArray.Select(m => m.GetType().FullName).OrderBy(t => t); ObjectDumper.Write(records); Book[] books = { new Book{ Title="万有引力之虹", Isbn="993748928", PageCount=300 }, new Book{ Title="解体概要", Isbn="325757665", PageCount=500 }, new Book{ Title="寂静的春天", Isbn="229911000", PageCount=200 } }; var records = books.Where(b => b.Isbn.Contains("9")).Select(b => b.Title); ObjectDumper.Write(records); List<Book> bList = new List<Book> { new Book{ Title="万有引力之虹", Isbn="993748928", PageCount=300 }, new Book{ Title="解体概要", Isbn="325757665", PageCount=500 }, new Book{ Title="寂静的春天", Isbn="229911000", PageCount=200 } }; var records = bList.Where(b => b.Isbn.Contains("9")).Select(b => b.Title); ObjectDumper.Write(records); Dictionary<string, int> bNary = new Dictionary<string, int> { { "sam", 12 }, { "corz", 22 }, { "korn", 53 }, }; var records = bNary.Where(o => o.Value > 20); ObjectDumper.Write(records); View Code 查询非泛型集合
只需要使用Cast<T>将非泛型集合转换为泛型即可。
ArrayList list = new ArrayList() { new Book{ Title="寂静的春天"}, new Book{ Title="万有引力之虹"}, new Book{ Title="解体概要"} }; var records = list.Cast<Book>().Select(b => new { bName= b.Title }); View Code 参数化查询
可在查询中使用变量,还可以动态构造查询,比如定义一个函数,函数以Func泛型委托做参数,通过条件测试传递不同的Lambda表达式。
<body> <select name="combobox"> <option value="0">查询标题</option> <option value="1">查询出版社</option> </select> <div> @ViewData["show"] </div> </body> View Code [HttpPost] public ActionResult Index(string combobox) { string recordsJson = string.Empty; switch (combobox) { case "0": recordsJson=ComboboxLambda(b => b.Title); break; case "1": recordsJson=ComboboxLambda(b=>b.Publisher.Name); break; } ViewData["show"] = recordsJson; return View(); } [NonAction] public string ComboboxLambda<T>(Func<Book,T> selector) { var records = SampleData.books.Select(selector); return JsonConvert.SerializeObject(records); } View Code LINQ查询是一系列的链式操作,所以完全可以根据条件动态增加查询,所以以下代码并不会发生覆盖而是追加。
[HttpPost] public ActionResult Index(int maxPage, string orderByTitle) { IEnumerable<Book> books = SampleData.books; if (maxPage != 0) { books = books.Where(b => b.PageCount > maxPage); } if (!string.IsNullOrEmpty(orderByTitle)) { books = books.OrderBy(b => b.Title); } books = books.Select(b => b); //查询会在符合条件的判断中形成链式操作 ViewData["show"] = JsonConvert.SerializeObject(books); return View(); } View Code 读取文件
一个txt文件存储了图书信息,为StreamReder添加一个扩展方法用于获取所有行,再通过LINQ查询将数据打包。
public static class StreamRederExtention { /// <summary> /// 读取每一行 /// </summary> /// <param name="source"></param> /// <returns></returns> public static IEnumerable<string> Lines(this StreamReader source) { string line; while (!string.IsNullOrEmpty(line = source.ReadLine())) { yield return line; } } } View Code public ActionResult Index() { string filePath = Server.MapPath("~/bookMessage.txt"); StreamReader reader = new StreamReader(filePath); using (reader) { var bookMsg = reader.Lines() .Where(line => !line.StartsWith("#")) //过滤掉首行 .Select(line => line.Split(',')) .Select(part => new { Isnb = part[0], title = part[1], publisher = part[2], author = part[3].Split(';').Select(authorPerson => authorPerson) }); ViewData["show"] = JsonConvert.SerializeObject(bookMsg); } return View(); } View Code
LINQ To XML
XObject类
AddAnnotation(object) //添加注释节点。 Annotation(Type) //获取第一个注释节点,类似行为的有Annotation<T>()、Annotations(Type)、Annotations<T>()。 方法 XNode类
表示项、注释、 文档类型、处理指令、文本节点。节点可以是项节点、属性节点、文本节点。
AddAfterSelf(object) //紧跟在此节点之后添加指定的内容 AddBeforeSelf(object) //紧跟在此节点之前添加指定的内容 Remove() //从父节点总移除自身 Ancestors() //获取当前节点的祖先元素节点集合 ElementsAfterSelf() //获取当前节点后面的兄弟元素节点集合 ElementsBeforeSelf() //获取当前节点的前面的兄弟元素节点集合 NodesAfterSelf() //获取当前节点后面的兄弟元素节点集合 NodesBeforeSelf() //获取当前节点前面的兄弟元素节点集合 方法 XContainer类
Nodes() //获取当前节点包含的所有子节点集合 Elements() //获取当前节点包含的所有子元素节点集合 Elements(XName) //获取当前节点包含的所有能匹配参数指定的XName的子元素节点集合 Element(XName) //获取当前节点包含的能匹配参数指定的XName的第一个子元素节点 Descendants() //获取当前节点包含的所有子代元素节点集合,即后代元素节点集合 DescendantNodes() //获取当前节点包含的所有子代节点集合,即后代节点集合 Descendants(XName) //获取当前节点包含的所有能匹配参数指定的XName的子代元素节点集合,即后代元素节点集合 Add(object) //添加子节 AddFirst(object) //将参数指定的节点添加为作为自身包含的第一个子节 RemoveNodes() //删除自身的所有子节 ReplaceNodes(object) //将自身包含的所有子节替换为参数指定的节点 ReplaceWith(object) //将自身替换为参数指定的节点 方法 XElement类
表示XML项节点。
XElement(XNameString, String | XElement | XAttribute | XProcessingInstruction | XComment | IEnumerable ) //XElement的构造函数,用于创建XML元素节点,参数2如果是String则成为元素节点包含的文本节点,否则可同时创建出后代元素节点 XNameString:元素节点名称的字符表示或XName对象 //示例1:使用函数式链式操作创建XML元素节点 XElement books = new XElement("books", new XElement("book", new XElement("author", "寒食"), new XElement("author", "寒食") ) ); //示例2:调用函数创建XML元素节点 XElement book = new XElement("book"); book.Add(new XElement("author","寒食")); book.Add(new XElement("author", "无垠")); XElement books = new XElement("books"); books.Add(book); //示例3:创建命名空间 XElement books = new XElement("{http://google.com/}books", new XElement("book", new XElement("author", "寒食"), new XElement("author", "寒食") ) ); //示例4:创建命名空间前缀 XElement books = new XElement("books", new XElement("book", new XAttribute(XNamespace.Xmlns + "1", ns), new XElement("author", "寒食"), new XElement("author", "寒食") ) ); Add(XElement) //添加子元素节点 Save() //保存XML文档 WriteTo(XmlWriter) //将元素节点写入XmlWriter中 Attribute(XName) //获取属性节点集合 Attribute(XName) //根据指定的属性节点名获取属性节点值 AncestorsAndSelf() //获取自身并包括其祖先元素节点集合 DescendantsAndSelf() //获取自身并包括其后代元素节点集合 RemoveAll() //移除所有后代 RemoveAttributes() //移除自身的所有属性节点 RemoveAnnotations(Type) //移除自身的所有注释节点 SetAttributeValue(XName, Object) //根据指定的属性节点名设置属性节点值 SetElementValue(XName, Object) //根据指定的属性节点名设置子元素节点的属性节点值 //==========静态方法========== load(Path, LoadOptions) //加载XML文档 //LoadOptions:可选的枚举,可能的值有: //None:不保留无意义的空白 //PreserveWhitespace:保留无意义的空白 //SetBaseUri:保留URI信息 //SetLineInfo:保留请求的行信息 //示例: try { XElement x = XElement.Load(Server.MapPath("/books.xml"), LoadOptions.PreserveWhitespace); // 可从URL、磁盘路径加载 } Parse() //从XML字符串解析出XElement //示例: XElement x = XElement.Parse(@" <book> <title>LINQ in Action</title> <author>Fabrice Marguerie</author> <author>Steve Eichert</author> <author>Jim Wooley</author> <publisher>Manning</publisher> <rating>4</rating> </book> "); 方法 XDocument类
表示XML文档,与XElement一样,它们都提供Load()、Parse()、Save()和WriteTo()方法,但此类可以包含更多信息,如包含一个根项的XElement、XML声明、XML文档类型和XML处理指令。如果使用函数式链式操作创建XML项,则使用XDocument与使用XElement创建XML项的语法格式是完全一样的。
//XDocument比XElement多了以下内容,其它则是一样的 XDocument doc = new XDocument("books", new XDeclaration("1.0", "utf-8", "yes"), // 表示XML文档版本、字符编码、是否是独立信息的节点 new XProcessingInstruction("XML-sylesheet", "friendly-rss.xsl"), // 表示XML文档处理指令的节点,此处为XML文档配置了一个样式表用以格式化XML文档以便在浏览器以友好的界面显示XML数据 new XDocumentType("HTML", "-//w3c//DTD HTML 4.01//EN", "http://www.w3.org/TR/html4/strict/dtd", null) // 表示XML文档类型声明的节点 ) ); View Code XAttribute类
Remove() //从父元素节点中移除自身 //==========属性========== Parent //获取父元素节点 方法 XName
表示项的名字或项属性的名字
读取XML的简单示例
<?xml version="1.0" encoding="utf-8" ?> <category name="知识"> <childcategory name="自然"> <books> <book>寂静的春天</book> <book>自然之力</book> </books> </childcategory> <childcategory name="宗教"> <books> <book>佛陀的证悟</book> </books> </childcategory> <childcategory name="社会"> <books> <book>智利天下写春秋</book> <book>文明的解析</book> </books> </childcategory> </category> XML public class DefaultController : Controller { public ActionResult Index() { XElement root = XElement.Load(Server.MapPath("~/books.xml"), LoadOptions.PreserveWhitespace); var childcategory = root.Element("childcategory"); // 获取第一个childcategory元素节点 var childcategoryAttri = childcategory.Attribute("name"); // 获取第一个childcategory的name属性节点 IEnumerable<XElement> books = childcategory.Element("books").Elements("book"); // 获取第一个childcategory所包含的第一个books元素节点包含的所有book元素节点 ViewData["childcategory"] = childcategory; ViewData["childcategoryAttri"] = childcategoryAttri; ViewData["childs"] = string.Join("", books.ToList()); // 输出XElement时会将它所包含的所有后代一并输出 // 输出 IEnumerable<XElement>元素节点集合时必须ToList后与字符相连 return View(); } } 读取XML // 获取每个book元素节点,从集合中过滤出其包含的文本为寂静的春天的元素节点 // (string)XElement可将元素节点转为其包含的文本 这样就可以执行一次判断 前提是该元素节点和包含的文本是在一行显示的 ViewData["show"] =string.Join("",root.Descendants("book").Where(book => (string)book == "寂静的春天")); 获取包含指定文本的项节点
LINQ To Entity
当查询数据库表的结果集时,比如在调用Where方法返回的结果集上再调用其它Linq扩展方法会抛出异常,这可能是因为数据库结果集已经返回,应将其ToList后转化为内存中的集合对象,然后才能使用Linq to Object的方法进行进一步的过滤。否则链式的Linq方法会被当做是在数据库执行查询 MyEntity.DrugsErpEntities dbcontext = new MyEntity.DrugsErpEntities(); //如果Where后没有ToList,而是直接调用Select方法将会引发异常 var list = dbcontext.UserManagers.Where(user => user.LoginName == "a").ToList().Select((p, i) => new { u = p.LoginName, id = p.UserId, index = i }).ToList(); DbSet<TEntity> 类
此类实现了IQueryable<T>接口,一系列的扩展方法可用于Linq查询。 Include() //使用预加载策略建立左联结查询,模型必须具有导航属性,此方法根据导航属性来查询与主实体所关联的其它实体,此方法会立即开启查询 MusicStoreDB db = new MusicStoreDB(); var albums = db.Albums.Include(a => a.Artist).Include(a => a.Genre); //Artist和Genre都是Album的导航属性,不需要像Join方法那般指定主外键,只需要指定导航属性即可建立左联结查询 //批量删除记录 //示例: public ContentResult DelBtch(string IDs) //IDs,需要被删除的记录的ID,如"1,15,32" { try { var records = DBContext.TbRights.RemoveRange(DBContext.TbRights.Where(t => IDs.Contains(t.TbRightId.ToString()))); DBContext.SaveChanges(); DBContext.Dispose(); return Content("{msg:'操作成功'}"); } catch { return Content("{msg:'操作失败'}"); } } AddRange() //批量添加记录 AddOrUpdate(TEntity[] ) //System.Data.Entity.Migrations命名空间中为DbSet<TEntity>定义的扩展,自动识别插入或更新,当实体主键在数据库表中不存在时视为插入,当实体主键在数据库表中存在时视为更新。在参数数组包含的实体的主键在数据库表中既有存在的也有不存在的情况时,没关系,该更新该插入,此方法自动帮你完成。 //注意:如果某个字段为空,也将插入或更新到数据库,如果数据库设置了不允许空则引发异常 //示例: var dirtyRecs = JsonConvert.DeserializeObject<List<TbRight>>(dirtyRecords); //包含了需要更新和需要插入的实体 DBContext.TbRights.AddOrUpdate(dirtyRecs.ToArray() ); //同时执行了插入和更新 插入数据前检测数据库是否已经具有一条完全相同的记录
#region 员工权限批量插入 /*xTbUserRight:需要插入数据库的记录的Json表示userIDs:以逗号分隔的员工ID的字符表示checkValues:以逗号分隔的权限ID的字符表示查询员工权限表时先对照userIDs和checkValues查出相同的记录,如果存在这样的记录则先删除它们最后将xTbUserRight转化为的实体记录集合插入数据库*/ public ContentResult AddTbUserRightBtch( string xTbUserRight , string xUserIDs , string xCheckValues ) { int [ ] userIDs = Array.ConvertAll ( xUserIDs.Split ( ',' ) , o => int.Parse ( o ) ); int [ ] checkValues = Array.ConvertAll ( xCheckValues.Split ( ',' ) , o => int.Parse ( o ) ); var newRecords = JsonConvert.DeserializeObject<List<TbUserRight>> ( xTbUserRight ); var oldRecords = DBContext.TbUserRights.Where ( t => userIDs.Contains ( t.UserId ) && checkValues.Contains ( t.TbRightId ) ); if ( oldRecords.Count ( ) != 0 ) { DBContext.TbUserRights.RemoveRange ( oldRecords ); } DBContext.TbUserRights.AddRange ( newRecords ); DBContext.SaveChanges ( ); return Content ( "{msg:'操作成功'}" ); } #endregion View Code 根据某个字段的数据集合查询出另一张表中对应的记录
int UserId = int.Parse ( xUserId ); //UserAuthority是用户权限表实体,它存储三个字段,主键、用户ID和用户权限ID,一个用户具有多个权限ID,结构如下: //PrimaryID UserID AuthorityID // 1 32 20 // 2 32 26 //Authority是权限表实体,它存储两个字段,主键和权限名称,结构如下: //AuthorityID AuthorityName // 32 ERP登录权限 //现在要查询出当前用户所具有的所有权限的记录 var userAuthorityID = DBContext.UserAuthority.Where ( t => t.UserID == UserId ).Select ( t => t.AuthorityID ).ToList ( ); //获取用户权限ID集合 var userInclud = DBContext.Authority.Where ( t => userAuthorityID.Contains ( t.AuthorityID ) ); //获取用户具有的权限记录 var userNotInclud = DBContext.Authority.Where ( t => !userAuthorityID.Contains ( t.AuthorityID ) ); //获取用户不具有的权限记录 View Code