Example #1
0
        /// <summary>
        /// 无实体链接删除添加
        /// </summary>
        /// <param name="context"></param>
        /// <param name="blogs"></param>
        public static void InserUpdateOrDeleteGraph(EFCoreDbContext context, Blog blogs)
        {
            var existingBlog = context.Blogs.Include(p => p.Posts).FirstOrDefault(b => b.Id == blogs.Id);

            if (existingBlog == null)
            {
                context.Add(blogs);
            }
            else
            {
                context.Entry(existingBlog).CurrentValues.SetValues(blogs);
                foreach (var post in blogs.Posts)
                {
                    var existingPost = existingBlog.Posts.FirstOrDefault(p => p.Id == post.Id);
                    if (existingPost == null)
                    {
                        existingBlog.Posts.Add(post);
                    }
                    else
                    {
                        context.Entry(existingPost).CurrentValues.SetValues(post);
                    }
                }

                foreach (var post in existingBlog.Posts)
                {
                    if (!blogs.Posts.Any(p => p.Id == post.Id))
                    {
                        context.Remove(post);
                    }
                }
            }

            context.SaveChanges();
        }
Example #2
0
        static void Main(string[] args)
        {
            using (var context = new EFCoreDbContext())
            {
                //TODO:EFCode不知道是否要创建,所以要手动去创建
                //context.Database.EnsureDeleted();
                //context.Database.EnsureCreated();

                //TODO:手动调用EntityFramework Core内置API创建
                //RelationalDatabaseCreator databaseCreator =
                //    (RelationalDatabaseCreator) context.Database.GetService<IDatabaseCreator>();
                //databaseCreator.CreateTables();
                //var student = context.Students.FirstOrDefault();

                //var s = new Student()
                //{
                //    Age = 1,
                //    Decimal = 1,
                //    Double = 1,
                //    Float = 1,
                //    CreateTime = DateTime.Now,
                //    Name = "chenjie"
                //};
                //context.Students.Add(s);
                //context.SaveChanges();

                //s.Name = "chenjielove";
                //context.SaveChanges();

                //context.Set<Customer>().AddRange(
                //    new Customer() { Name = "111"},
                //    new Customer() { Name = "222"}
                //    );
                //context.SaveChanges();


                //context.Blogs.Add(new Blog("http://www.cnblogs.com") {Name = "chenjie"});
                //context.SaveChanges();
                //foreach (var blog in context.Blogs)
                //{
                //    Console.WriteLine($"{blog.Id}{blog.Name}{blog.Url}");
                //}

                //var student=new Student()
                //{
                //    Age=1,
                //    Name = "chenjie",
                //    CreateTime = DateTime.Now
                //};
                //var course=new Course()
                //{
                //    Name = "EntityFramework Core",
                //    Introduce = "轻量级、可扩展、跨平台",
                //    CreatedTime = DateTime.Now
                //};
                //student.AddCourse(course);
                //context.Students.Add(student);
                //context.SaveChanges();

                //var courses = context.Set<Course>().Where(d => EF.Property<int>(d, "StudentId") == 1).ToList();
                //var course=new Course
                //{
                //    Introduce = "EntityFramework Core 2.0",
                //    Name = "EF Core"
                //};
                //context.Entry(course).Property("CreateTime").CurrentValue = DateTime.Now;
                //context.SaveChanges();
                //var blogs = context.Blogs.Include(d => d.Post).ToList();

                //var blog = context.Blogs.Include(d => d.Post).IgnoreQueryFilters().AsNoTracking().ToList();
                //var blogId = 1;
                //var posts = context.Set<Post>().Where(d => EF.Property<int>(d, "BlogId") == blogId);
                //var tags = new[]
                //{
                //    new Tag{Text="1"},
                //    new Tag{Text="2"},
                //    new Tag{Text="3"},
                //    new Tag{Text="4"},
                //    new Tag{Text="5"},
                //};
                //var posts = new[]
                //{
                //    new Post{Name="1"},
                //    new Post{Name="2"},
                //    new Post{Name="3"},
                //    new Post{Name="4"},
                //    new Post{Name="5"},
                //};

                //context.AddRange(new PostTag { Posts = posts[0], Tags = tags[0] },
                //    new PostTag { Posts = posts[1], Tags = tags[1] },
                //    new PostTag { Posts = posts[2], Tags = tags[2] },
                //    new PostTag { Posts = posts[3], Tags = tags[3] },
                //    new PostTag { Posts = posts[4], Tags = tags[4] });
                //context.SaveChanges();

                //var postss = context.Set<Post>().Include("PostTags.Tag").ToList();

                //context.Payments.Add(new CashPayment {Amount = 2M, Name = "Tom"});
                //context.Payments.Add(new CashPayment {Amount = 1000M, Name = "Jim"});

                //context.Payments.Add(new CreditcardPayment()
                //{
                //    Amount = 200000,
                //    Name = "招商银行",
                //    CreditcardNumber = "041647181912"
                //});
                //context.SaveChanges();

                //var payments = context.Payments.ToList();
                //foreach (var payment in payments)
                //{
                //    Console.WriteLine($"{payment.Name}{payment.Amount}{payment.GetType().Name}");
                //}

                //var payments = context.Payments.ToList();
                //foreach (var payment in context.Payments.OfType<CreditcardPayment>())
                //{
                //    Console.WriteLine($"{payment.Name}{payment.Amount}{payment.GetType().Name}");
                //}
                //TODO: 当使用主键查询时使用Find方法性能会更好
                //var blog = context.Blogs.Find(1);
                //var blogs = context.Blogs.FirstOrDefault(d => d.Id == 1);
                //TODO:复合主键
                //var productCategory = context.Blogs.Find(1, 1);
                //TODO:利用Find或者FindAsync方法不能进行饥饿加载(Include),但是我们任然能够通过上下文的Entry方法中的Navigations属性加载导航属性实现饥饿加载


                //var student = context.Students.Find(Convert.ToInt32(3));
                //foreach (var navigation in context.Entry(student).Navigations)
                //{
                //    navigation.Load();
                //}

                //TODO:在继承映射TPH模式中,可以用OfType方法转换为具体类,所以此方法与查询运算符等值条件等价
                //var patments = context.Payments.OfType<CashPayment>();
                //Console.WriteLine(patments.FirstOrDefault()?.Name);
                //TODO:也可以用Cast进行转换与OfType的区别是,Cast将翻译成In子句
                //var payments = context.Payments.Cast<CashPayment>();
                //Console.WriteLine(payments.FirstOrDefault()?.Name);
                //TODO:EF Code不支持使用OfType和Cast转换原始类型
                //var paymentss = context.Payments.Select(d => d.PaymentId).OfType<string>();
                //Console.WriteLine(paymentss);
                //TODO:C# 中可以使用if和as来进行类型转换。如果一个对象是某个类型或是其父类型,就返回true否则返回false,Is永远不会抛出异常,As会
                //TODO:Is进行类型转换等同于Cast在sql中都会翻译成in子句
                //var payments = context.Payments.Where(d => d is CashPayment);
                //Console.WriteLine(payments.FirstOrDefault()?.Name);
                //TODO:调用Select会翻译成Select子句,投影不仅支持实体,同时支持匿名函数
                //var paymentss = context.Payments.Select(d => d.Name + " ");
                //Console.WriteLine(paymentss.FirstOrDefault());
                //TODO:DefaultIfEmpty常用于左连接,若查询序列为空,则返回实例类型默认值
                //var blogs = context.Blogs.Where(d => d.Id == 0).DefaultIfEmpty();
                //Console.WriteLine(blogs.FirstOrDefault()==default(Blog));
                //TODO:DefaultIfEntity还有重载可接受一个指定的默认值,在EFCore中将不会翻译为SQL,而是在本地检查结果,如果没有行就会产生指定的默认值
                //var defaultBlog = new Blog(){Name = nameof(Blog)};
                //var blogss = context.Blogs.Where(d => d.Id == 0).DefaultIfEmpty(defaultBlog);
                //Console.WriteLine(blogss.FirstOrDefault()?.Name);
                //TODO:EFCore还不支持分组,它只优化了GroupBy,将GroupBy中的OrderBy子句进行了翻译,将SQL执行结果读取到本地,逐一进行分组
                var blogs = context.Blogs.GroupBy(d => d.Id);
                Console.WriteLine(blogs.FirstOrDefault()?.FirstOrDefault()?.Name);
                //TODO:会翻译为inner join
                var outerBlogs = context.Blogs;
                var innerPosts = context.Set <Post>();

                var outerBlogQuery = outerBlogs.Join(innerPosts, b => b.Id, p => p.BlogId,
                                                     ((blog, post) => new { Id = blog.Id, Name = blog.Name }));
                Console.WriteLine(outerBlogQuery.FirstOrDefault()?.Name);
                //TODO:使用Select和SelectMany可以实现CROSS JOIN 交叉查询(求两个表的笛卡尔积)
                var outerBlogQuert2 = outerBlogs.Select(b => new
                {
                    Id    = b.Id,
                    Name  = b.Name,
                    Posts = innerPosts.Where(p => p.BlogId == b.Id)
                }).SelectMany(collectionSelector: b => b.Posts,
                              resultSelector: (b, p) => new { Id = b.Id, Name = b.Name });
                Console.WriteLine(outerBlogQuert2.FirstOrDefault()?.Name);
                //TODO:GroupJoin最终被翻译成LeftJoin
                var outerBlogQusert3 = outerBlogs.GroupJoin(inner: innerPosts, outerKeySelector: b => b.Id,
                                                            innerKeySelector: p => p.BlogId,
                                                            resultSelector: (b, p) => new { Id = b.Id, Name = b.Name, Posts = b.Posts });
                Console.WriteLine(outerBlogQusert3.FirstOrDefault()?.Name);
                //TODO:EFCore中不支持连接翻译SQL,支持本地和合并。下面代码会抛出异常。
                var first  = context.Blogs.Where(item => item.Id >= 1);
                var second = context.Blogs.Where(item => item.Id <= 2);
                var blogs2 = first.Concat(second).Select(d => new { Id = d.Id, Name = d.Name });
                Console.WriteLine(blogs2.FirstOrDefault()?.Name);
                //TODO:下面为本地合并
                var first1  = context.Blogs.Where(item => item.Id >= 1).Select(d => d.Name);
                var second1 = context.Blogs.Where(item => item.Id <= 2).Select(d => d.Name);
                var name    = first.Concat(second);
                Console.WriteLine(name.FirstOrDefault());
                //TODO:Skip和Take会转换成SQL中的OFFSET和LIMIT分页关键字
                var blogs3 = context.Blogs.Skip(1).Take(10);
                Console.WriteLine(blogs3.DefaultIfEmpty());
                //TODO:EFCore中会将Contains转换成SQL中的In谓词
                var blogs4 = context.Blogs.Select(d => d.Id).Contains(1);
                Console.WriteLine(blogs4);
                //TODO:EFCore中会将字符串的Contains转换成CHARINDEX
                var blogs5 = context.Blogs.Select(d => d.Name.Contains("J"));
                Console.WriteLine(blogs5.FirstOrDefault());
                //TODO:EFCorez中会将数组集合的Contains翻译成In子句
                var nameArray = new string[] { "a", "b", "c" };
                var blogs6    = context.Blogs.Where(item => nameArray.Contains(item.Name));
                Console.WriteLine(blogs6.FirstOrDefault()?.Name);
                //TODO:EFCore中会将Any翻译EXISTS将All翻译成NOT EXISTS
                var blogs7 = context.Blogs.Any(i => i.Id == 1);
                var blogs8 = context.Blogs.All(item => item.Id == 1);
                Console.WriteLine(blogs7);
                Console.WriteLine(blogs8);
                //TODO:在EFCore中使用Include可执饥饿加载,如果有多个导航属性,可以用Include,如果导航属性需要饥饿加载使用ThenInclude
                var blogs9 = context.Blogs.Include(item => item.Posts);
                //TODO:如果在Include后更改了查询结果,那么Include将会被忽略
                var blogs10 = context.Blogs.Include(item => item.Posts).Select(b => new { ID = b.Id });
                //TODO:EFCore1.1中添加的显示加载
                var blogs11 = context.Blogs.FirstOrDefault();
                context.Entry(blogs11).Collection(b => b.Posts).Load();
                //TODO:调用原生SQL
                var blogs12 = context.Blogs.FromSql <Blog>("select * from blogs").ToList();
                //TODO:也可以使用字符串插值
                var blogs13 = context.Blogs.FromSql($"select * from blogs where Id={1}");
                //TODO:使用 FormattableString可以防止SQL注入 。调用原,生查询后同样可以用Include关联
                FormattableString formattable = $"select * from blogs where Id={1}";
                var blogs14 = context.Blogs.FromSql(formattable).Include(b => b.Posts).ToList();
                //TODO:原生执行增删改操作
                var commandSql   = "Insert into blog(name,url) values(@name,@url)";
                var sqlParameter = new SqlParameter[]
                {
                    new SqlParameter("@name", System.Data.SqlDbType.NVarChar),
                    new SqlParameter("@url", System.Data.SqlDbType.NVarChar)
                };
                sqlParameter[0].Value = "张三";
                sqlParameter[1].Value = "www.chenjieloveyou.com";
                context.Database.ExecuteSqlCommand(commandSql, sqlParameter);
                //批处理声明
                var blogs15 = new Blog
                {
                    CreatedTime  = DateTime.Now,
                    ModifiedTime = DateTime.Now,
                    Name         = "陈杰"
                };
                context.ChangeTracker.TrackGraph(blogs15, node =>
                {
                    var entry = node.Entry;
                    if ((int)entry.Property("Id").CurrentValue < 0)
                    {
                        entry.State = EntityState.Added;
                        entry.Property("Id").IsTemporary = true;
                    }
                    else
                    {
                        entry.State = EntityState.Modified;
                    }
                });

                var excetingBlogs = context.Blogs.Find(1);
                if (excetingBlogs == null)
                {
                    context.Add(blogs);
                }
                else
                {
                    context.Entry(excetingBlogs).CurrentValues.SetValues(blogs);
                }

                context.SaveChanges();
                //TODO:无实体更新
                var blogs17 = context.Blogs.Include(item => item.Posts).FirstOrDefault(item => item.Id == 2);
                blogs17.Name = "aaa";
                blogs17.Posts.All(p =>
                {
                    p.Name = "bbb";
                    return(true);
                });
                context.Update(blogs17);
                var result = context.SaveChanges();

                //TODO:无实体更新无主键
                var blogs18 = context.Blogs.Include(item => item.Posts).FirstOrDefault(item => item.Id == 2);

                if (blogs18 == null)
                {
                    context.Blogs.Add(blogs17);
                }
                else
                {
                    context.Entry(blogs18).CurrentValues.SetValues(blogs17);
                    foreach (var post in blogs17.Posts)
                    {
                        var nowPost = blogs18.Posts.FirstOrDefault(item => item.Id == post.Id);
                        if (nowPost == null)
                        {
                            blogs18.Posts.Add(post);
                        }
                        else
                        {
                            context.Entry(nowPost).CurrentValues.SetValues(post);
                        }
                    }
                }

                context.SaveChanges();
                //TODO:每个实体查询EF都会创建快照去追踪实体,如果要关闭追踪使用AsNoTracking()方法
                var blogs19 = context.Blogs.AsNoTracking().ToList();
                //TODO:使用我们重写的方法优化性能添加时,不需要快照追踪
                for (int i = 0; i < 1000; i++)
                {
                    context.AddRange(new Blog()
                    {
                        Name = i.ToString()
                    });
                }

                context.SaveChanges(true);

                //TODO:在EF中我们可以用Contains,StartsWith,EndWith来做模糊查询,不过Contains转换成SQL之后是Charindex,StartsWith会生成夹带双重判断的SQL,一遍会通过通配符过滤,灵异方面会通过LEFT函数从左边截取长度等于字符串长度的条件,EndsWith不会用%通配符,而是使用Right函数从最后开始截取
                //TODO:有了EF.Function.Like我们很方便的自定义模糊查询逻辑
                var selectStr      = "abcd";
                var blogsStartWith = blogs19.Where(d => d.Name.StartsWith("J")).ToList();
                var blogsEndWith   = blogs19.Where(d => d.Name.EndsWith("J")).ToList();
                var blogsLike      = blogs19.Where(d => EF.Functions.Like(d.Name, "J%")).ToList();
                var blogsLikeStr   = blogs19.Where(d => EF.Functions.Like(d.Name, $"[{selectStr}]%"));
                //TODO:我们可以用like的重载方法处理转义字符,最终会翻译成ESCAPE
                var blogsLikeescape = blogs19.Where(d => EF.Functions.Like(d.Name, @"\J%", @"\")).ToList();
                //TODO:EFCore重要特性之一显示编译查询
                var query      = EF.CompileQuery((EFCoreDbContext db, int id) => db.Blogs.FirstOrDefault(c => c.Id == id));
                var queryBlog  = query(context, 1);
                var queryBlog2 = query(context, 1);
                //TODO:自定义验证
                if (context.ExecuteValidator().Any())
                {
                    foreach (var error in context.ExecuteValidator())
                    {
                        Console.WriteLine(error.ErrorMessage);
                    }
                }
            }

            RunText(regularTest: (blogIds) =>
            {
                using (var db = new EFCoreDbContext())
                {
                    foreach (var id in blogIds)
                    {
                        var customer = db.Blogs.FirstOrDefault(c => c.Id == id);
                    }
                }
            }, compiledTest: (blogIds) =>
            {
                var query = EF.CompileQuery((EFCoreDbContext db, int id) => db.Blogs.FirstOrDefault(c => c.Id == id));
                using (var db = new EFCoreDbContext())
                {
                    foreach (var id in blogIds)
                    {
                        var customer = query(db, id);
                    }
                }
            });
            //TODO:使用不依赖注入构造DbContextOptions
            _contextOptions = new DbContextOptionsBuilder().UseSqlServer(args[0]).Options;
        }