導航屬性 導航屬性是作為.NET ORM核心功能中的核心,在SqlSugar沒有支持導航屬性前,都說只是一個高級DbHelper, 經過3年的SqlSugar重構已經擁有了一套 非常成熟的導航屬性體系,本文不是重點講SqlSugar而是重點講導航屬性的作用,讓更多寫Sql人還未使用ORM的人瞭解到O ...
導航屬性
導航屬性是作為.NET ORM核心功能中的核心,在SqlSugar沒有支持導航屬性前,都說只是一個高級DbHelper, 經過3年的SqlSugar重構已經擁有了一套
非常成熟的導航屬性體系,本文不是重點講SqlSugar而是重點講導航屬性的作用,讓更多寫Sql人還未使用ORM的人瞭解到ORM的作用。
1.複雜的查詢過濾
用戶根據許可權過濾,用戶根據組織過濾 等這種多對多情況用SQL就相當複雜 ,例如:用SQL寫一個多對多過濾就要聯3個表(主表 中間表 從表),如果
Where中用到多個多對多或者嵌套多對多那寫SQL簡直就是惡夢 (一對多和一對一也有提升,沒有多對多明顯)
//EF CORE查詢 var Persons= dbContext.Person //需要定義DbSet才能點出來 .Where(it=>it.Files.Any(y=>y.ChildFiles.Any(s=>s.name=="A"))).ToList() //SqlSugar 查詢 var Persons= dbContext.Queryable<Person>() .Where(it=>it.Files.Any(y=>y.ChildFiles.Any(s=>s.name=="A"))).ToList()
用SQL寫如下:
SELECT p.* FROM Person p WHERE EXISTS ( SELECT 1 FROM PersonFile pf INNER JOIN File f ON pf.FileId = f.FileId INNER JOIN PersonFile pf2 ON f.FileId = pf2.FileId WHERE pf.PersonId = p.PersonId AND pf2.PersonId IN ( SELECT p2.PersonId FROM Person p2 INNER JOIN PersonFile pf3 ON p2.PersonId = pf3.PersonId INNER JOIN File f2 ON pf3.FileId = f2.FileId WHERE f2.name = 'A' ) )
像SAAS系統這種多對多用的非常多,特別在組織、用戶、角色、文件等無處理不在,這也是為什麼要用ORM的原因
2.複雜的表單提交
如果您的人事管理需要包含更多的信息,例如學歷和工作經驗等欄位,您可以在代碼中添加相應的實體和關聯。
假設您有以下實體:人員(Person)、部門(Department)、職位(Position)、學歷(Education)和工作經驗(WorkExperience)。
var person = new Person { // 設置人員屬性... Department = new Department { // 設置部門屬性... }, Position = new Position { // 設置職位屬性... }, Education = new Education { // 設置教育屬性... }, WorkExperience = new WorkExperience { // 設置工作經歷屬性... } };
代碼如下:
//SqlSugar 導航插入 db.InsertNav(person) .Include(z1 => z1.Department) .Include(z1 => z1.Position) .Include(z1 => z1.Education) .Include(z1 => z1.WorkExperience) .ExecuteCommand();//導航插入 一句就能搞定,先插入主表,然後在根據主表的主鍵在插入從表,特別是自增列用導航代碼清爽很多
3.多層級結構的查詢
因為Sql本身就不支持對多層級結構查詢,所以不用ORM想實現高性能的多層級結構是需要花大量精力去優化和寫代碼的
//EF CORE查詢 var Persons= dbContext.Person .Include(z1 => z1.Department) .Include(z1 => z1.Position) .Include(z1 => z1.Education) .Include(z1 => z1.WorkExperience).ToList()
EF Core導航屬性配置
EF多對多
public class Student { public int StudentId { get; set; } public string StudentName { get; set; } // 其他學生屬性... public virtual ICollection<Course> Courses { get; set; } } public class Course { public int CourseId { get; set; } public string CourseName { get; set; } // 其他課程屬性... public virtual ICollection<Student> Students { get; set; } } public class StudentCourse { public int CourseId { get; set; } public int StudentId { get; set; } } // 配置多對多關係 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Student>() .HasMany(s => s.Courses) .WithMany(c => c.Students) .UsingEntity(j => j.ToTable("StudentCourse")); }
EF一對多和一對一
public class Department { public int DepartmentId { get; set; } public string DepartmentName { get; set; } // 其他部門屬性... public virtual ICollection<Employee> Employees { get; set; } } public class Employee { public int EmployeeId { get; set; } public string EmployeeName { get; set; } // 其他員工屬性... public int DepartmentId { get; set; } public virtual Department Department { get; set; } } // 配置一對多關係 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Department>() .HasMany(d => d.Employees) .WithOne(e => e.Department) .HasForeignKey(e => e.DepartmentId); }
SqlSugar導航屬性配置
SqlSugar多對多
//實體 public class ABMapping1 { [SugarColumn(IsPrimaryKey = true)]//中間表可以不是主鍵 public int AId { get; set; } [SugarColumn(IsPrimaryKey = true)]//中間表可以不是主鍵 public int BId { get; set; } } public class A1 { [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } public string Name { get; set; } [Navigate(typeof(ABMapping1), nameof(ABMapping1.AId), nameof(ABMapping1.BId))]//註意順序 public List<B1> BList { get; set; }//只能是null不能賦預設值 } public class B1 { [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } public string Name { get; set; } [Navigat(typeof(ABMapping1), nameof(ABMapping1.BId), nameof(ABMapping1.AId))]//註意順序 public List<A1> AList { get; set; }//只能是null不能賦預設值 }
Sqlugar一對一和一對多
//實體 public class StudentA { [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public int StudentId { get; set; } public string Name { get; set; }public int SchoolId { get; set; } [Navigate(NavigateType.OneToOne, nameof(SchoolId))]//一對一 SchoolId是StudentA類裡面的 public SchoolA SchoolA { get; set; } //不能賦值只能是null } public class SchoolA { [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public int Id{ get; set; } public string SchoolName { get; set; } [Navigate(NavigateType.OneToMany, nameof(BookA.studenId))]//一對多 BookA表中的studenId public List<BookA> Books { get; set; }//註意禁止給books手動賦值 }
SqlSugar 2023年導航新功能
SqlSugar 第一層自動導航
var list3 = db.Queryable<UnitaStudentA>() .IncludesAllFirstLayer().ToList();//有重載可以排除不想要的 //排除說明: //IncludesAllFirstLayer(nameof(UnitaStudentA.ProjectPhases)) //這樣就是排除ProjectPhases的導航屬性 //可以排除多個 //IncludesAllFirstLayer("a","b") //自動導航如果有重覆的情況: 誰在前面執行哪個 var list3 = db.Queryable<UnitaStudentA>() .Includes(it=>it.Order.Where(s=>s.id==1).ToList()) .IncludesAllFirstLayer().ToList();//自動導航和Order重覆 //根據名字導航 db.Queryable<Order>() //等同於Includes(it=>it.ProjectPhases) .IncludesByNameString(nameof(Order.ProjectPhases)).ToList()
SqlSugar第二層半自動
//自動寫法,Books下麵的A和B都會查詢出來 .IncludesAllSecondLayer(x=>x.Books) //自動只能有這麼多層次,更深層級需要手動寫法 //手動寫法 .Includes(x => x.Books,x=>x.A) .Includes(x => x.Books,x=>x.B)
SqlSugar導航DTO轉換
在前二年SqlSugar導航只能說夠用,並不算好用,今年重點將導航DTO進行了強化
//簡單的用法 5.1.4.71 var list = db.Queryable<Student_004>() .Includes(x => x.books) .Select(x => new Student_004DTO { books = x.books }, true)//true是自動映射其他屬性,匿名對象需要手動 .ToList(); //Mapster轉換 5.1.4.71 var list = db.Queryable<Student_004>() .Includes(x => x.books) .Select(x => new Student_004DTO { name=x.Name, books = x.books.Adapt<List<BooksDTO>>() //導航對象用 Mapster轉換 (NUGET安裝) }) .ToList(); //DTO中用方法 5.1.4.71 var list = db.Queryable<Student_004>() .Includes(x => x.books) .Select(x => new Student_004DTO { name=x.Name, //可以是C#任何方法結尾 bookIds=x.books.Select(it=>it.id).ToList() }) .ToList(); //聯表查詢用DTO寫法 5.1.4.71 var list5= db.Queryable<Student_004>() .Includes(x => x.school_001, x => x.rooms) .Includes(x => x.books) .LeftJoin<Order>((x, y) => x.Id==y.sid) .Select((x,y) => new Student_004DTO { SchoolId = x.SchoolId, books = x.books, school_001 = x.school_001, Name=y.Name }) .ToList();
當你遇到繁瑣的資料庫操作時,.NET SQLSugar就像是一雙溫暖的手,幫你輕鬆解決難題。它是一個強大的工具,讓你的資料庫管理變得更簡單、更高效。下載.NET SQLSugar吧,讓它成為你的數據之路上的得力助手,讓你的編程之旅充滿感動與喜悅!
原碼下載: https://github.com/DotNetNext/SqlSugar
總結:
.NET中無論是EF CORE還是SQLSUGAR 使用了導航屬性都不再需要費心寫繁瑣的SQL語句,只需簡單地調用導航屬性,便能輕鬆獲取所需的數據。讓我們一起追隨這份感動,選擇使用導航屬性,讓編程的旅途更加愉悅,讓代碼的世界充滿美好與便捷!