项目开发中的一些注意事项以及技巧总结

 

1、jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View()、PartialView()等,只能返回json以及content等,但是一般我们在开发的时候也是使用json返回的,此时如果需要渲染界面或者是加载局部视图,我们可以在ajax的success的事件中使用$.html()来渲染后台给前端传的View()数据。一开始我遇到这个问题的时候还很纳闷,为什么ajax给后端穿了POST之后,不能加载局部页面,后来一想,是不是因为ajax是异步请求的原因,于是我把ajax的同步开关打开了,同时将后台传输的视图数据直接使用$html()就渲染到了前端页面。具体请参考:https://blog.csdn.net/m0_37302219/article/details/78272081

2 、后端MVC架构,一般前端都是使用Razor视图,使用@来加载后台传过来的数据比如ViewData,以及ViewBag等。此时,我建议在后端的C#中,我们给ViewBag赋值了之后,在前端的cshtml页面中这么做:
@{
List<T> xxx = ViewBag.xxx;
T xxx = ViewBag.xxx;
}
然后直接使用显式类型的变量来做处理。

3、EF Core中,尤其要注意多对多的关联属性的使用。如果使用不当就会加载不出来数据,直接会出一个null值,在这里请参考
https://blog.oneunicorn.com/2017/09/25/many-to-many-relationships-in-ef-core-2-0-part-1-the-basics/
认真的跟着这个博客做一遍就可以理解了。

4、EF Core中,当我们使用code First建模方式生成数据库时,如果生成数据库有问题了(当然一般是没有问题的,但是我就遇到了,可能也是我操作不当)我强烈建议,不要删除这个生成有问题的数据库,千万不要觉得删除了之后,可以再生成一遍,会出问题的。具体请看
http://www.cjjjs.com/paper/lkkj/2018711212518513.html

5、EF Core下一对多的关联中,需要注意(我不怎么用过EF,也不知道在EF中是不是很正常,在这里仅仅说EF Core,可能两者在我要说的这点上是一致的)。我们以官方为例:https://docs.microsoft.com/en-us/ef/core/get-started/aspnetcore/existing-db
一个博客(Blog)对应多个文章(Post),一篇文章对应一个博客(Blog)。此时,当我们使用上下文来获取数据库数据时,代码如下:
List<Blog> Blogs = _context.Blogs.ToList(); 
List<Post> Posts = _context.Posts.ToList(); // 如果不写这句代码,不从数据库里面加载处理关联属性Post的数据,那么Blogs里面的Post关联属性也将会是null值,这点是要特别注意的,只有写了这句代码,Blogs类型的关联属性Post才能有数据。

6、项目中一定要设计好数据库,一般来讲如果有级联关系的,就设置为两个表(这里的级联关系我是这么定义的:假设一个类别下有多条数据,这就是一个级联关系,就像是一个省份下面有多个城市)。在实体方面,我们可以认为是一对多关系,如果是一对多关系,我们就建两个表。设计好了数据表,对我们的开发有着莫大的好处,有时候多加一个字段和少一个字段完全不一样。

7、建议在列表数据中使用ForEach来遍历,也就是一般的List<T>变量,使用List<T>.ForEach来遍历数据处理逻辑

基于Repository模式设计项目架构—你可以参考的项目架构设计

 

关于Repository模式,直接百度查就可以了,其来源是《企业应用架构模式》。
我们新建一个Infrastructure文件夹,这里就是基础设施部分,EF Core的上下文类以及Repository层都放在这里面。
新建一个IReposotory的接口,其内容就是封装了基本的CRUD:

public interface IRepository<TEntity> where TEntity : class
 {
    ///获取当前实体的查询数据集
    IQueryable<TEntity> Entities{get;} 

    ///获取当前实体的数据集
    DbSet<TEntity> DbEntities{get;} 

 /// <summary>
 /// Gets all objects from database
 /// </summary>
 /// <returns></returns>
 IQueryable<TEntity> All(); 

 /// <summary>
 /// Gets objects from database by filter.
 /// </summary>
 /// <param name="predicate">Specified a filter</param>
 /// <returns></returns>
 IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> predicate); 

 /// <summary>
 /// Gets objects from database with filting and paging.
 /// </summary>
 /// <param name="filter">Specified a filter</param>
 /// <param name="total">Returns the total records count of the filter.</param>
 /// <param name="index">Specified the page index.</param>
 /// <param name="size">Specified the page size</param>
 /// <returns></returns>
 IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> filter, out int total, int index = 0, int size = 50); 

 /// <summary>
 /// Gets the object(s) is exists in database by specified filter.
 /// </summary>
 /// <param name="predicate">Specified the filter expression</param>
 /// <returns></returns>
 bool Contains(Expression<Func<TEntity, bool>> predicate); 

 /// <summary>
 /// Find object by keys.
 /// </summary>
 /// <param name="keys">Specified the search keys.</param>
 /// <returns></returns>
 TEntity Find(params object[] keys); 

 /// <summary>
 /// Find object by specified expression.
 /// </summary>
 /// <param name="predicate"></param>
 /// <returns></returns>
 TEntity Find(Expression<Func<TEntity, bool>> predicate); 

 /// <summary>
 /// Create a new object to database.
 /// </summary>
 /// <param name="t">Specified a new object to create.</param>
 /// <returns></returns>
 int Create(TEntity t); 

 /// <summary>
 /// Delete the object from database.
 /// </summary>
 /// <param name="t">Specified a existing object to delete.</param>
 void Delete(TEntity t); 

 /// <summary>
 /// Delete objects from database by specified filter expression.
 /// </summary>
 /// <param name="predicate"></param>
 /// <returns></returns>
 int Delete(Expression<Func<TEntity, bool>> predicate); 

 /// <summary>
 /// Update object changes and save to database.
 /// </summary>
 /// <param name="t">Specified the object to save.</param>
 /// <returns></returns>
 int Update(TEntity t); 

 /// <summary>
 /// Select Single Item by specified expression.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="expression"></param>
 /// <returns></returns>
 TEntity FirstOrDefault(Expression<Func<TEntity, bool>> expression);
 }

创建一个基类,用来实现IRepository接口,同时作其余的Repository的基类

public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
 {
 protected readonly DbContext Context; 

 public BaseRepository(DbContext context)
 {
 Context = context;
 } 

/// 获取当前实体的查询数据集
public IQueryable<TEntity> Entities
{
get { return Context.Set<TEntity>().AsQueryable(); }
} 

/// 获取当前实体
public IQueryable<TEntity> Entities
{
get { return Context.Set<TEntity>(); }
} 

 public TEntity FirstOrDefault(Expression<Func<TEntity, bool>> expression)
 {
 return All().FirstOrDefault(expression);
 } 

 public IQueryable<TEntity> All()
 {
 return Context.Set<TEntity>().AsQueryable();
 } 

 public virtual IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> predicate)
 {
 return Context.Set<TEntity>().Where<TEntity>(predicate).AsQueryable<TEntity>();
 } 

 public virtual IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> filter, out int total, int index = 0,
 int size = 50)
 {
 var skipCount = index * size;
 var resetSet = filter != null
 ? Context.Set<TEntity>().Where<TEntity>(filter).AsQueryable()
 : Context.Set<TEntity>().AsQueryable();
 resetSet = skipCount == 0 ? resetSet.Take(size) : resetSet.Skip(skipCount).Take(size);
 total = resetSet.Count();
 return resetSet.AsQueryable();
 } 

 public virtual int Create(TEntity TObject)
 {
 Entities.Add(TObject);
 Context.SaveChanges();
 } 

 public virtual int Delete(TEntity TObject)
 {
 Entities.Remove(TObject);.
 Context.SaveChanges();
 } 

 public virtual void Update(TEntity TObject)
 {
 try
 {
 var entry = Context.Entry(TObject);
 Context.Set<TEntity>().Attach(TObject);
 entry.State = EntityState.Modified;
 }
 catch (OptimisticConcurrencyException ex)
 {
 throw ex;
 }
 } 

 public virtual int Delete(Expression<Func<TEntity, bool>> predicate)
 {
 var objects = Filter(predicate);
 foreach (var obj in objects)
 Context.Set<TEntity>().Remove(obj);
 return Context.SaveChanges();
 } 

 public bool Contains(Expression<Func<TEntity, bool>> predicate)
 {
 return Context.Set<TEntity>().Any(predicate);
 } 

 public virtual TEntity Find(params object[] keys)
 {
 return Context.Set<TEntity>().Find(keys);
 } 

 public virtual TEntity Find(Expression<Func<TEntity, bool>> predicate)
 {
 return Context.Set<TEntity>().FirstOrDefault<TEntity>(predicate);
 }
 }

新建一个实体类的接口:

public interface IStudentRepository : IRepository<Student>
 {
 int AddStudent(Student student);
 }

然后我们创建一个实体类的Repository:

public class StudentRepository : BaseRepository<Student>, IStudentRepository
 {
 private readonly SchoolContext _context; 

 public StudentRepository(SchoolContext context)
 : base(context)
 {
 _context = context;
 } 

int AddStudent(Student student)
{
_context.Create(student);
}
 }

在这里就已经做好了我们要做的了。接下来的就是注入依赖、在控制器里面的使用了。

我们完全可以自己来定制自己的Repository模式下的项目。其实整个的架构没有什么,我们只是将所有的CRUD操作封装到了IRepository接口里面,然后在BaseRepository中实现了一遍,而且如果你细心的话,你会发现IRepository里面的CRUD操作都是基于已有的扩展方法里面的,就是linq扩展方法的Add等源码,同时我们在BaseRepository类中,提供了DbSet<TEntity>属性以及查询数据集IQueryable<DbSet<TEntity>>,这也是有必要的,可以省却我们很多不必要的代码,因为我们所有的CRUD都是基于这两个的。然后我们基于BaseRepository来实现实体类的Repository,同时继承按需增加的IEntityRepository接口。但是在这里要注意,我们将DbContext的子类都放在了Infrastructure文件夹里面,是因为,一般我们继承自DbContext的子类都是操作数据库的中间类,属于基础设施一块,所以将其放在Infrastructure文件夹比较合适。

参考资料:
MVC实用架构设计(三)——EF-Code First(1):Repository,UnitOfWork,DbContext

分享基于Entity Framework的Repository模式设计(附源码)

《ASP.NET MVC框架揭秘》源码中的示例项目源码 S1402

EF Core中的多对多映射如何实现?

 

EF 6.X中的多对多映射是直接使用HasMany-HasMany来做的。但是到了EF Core中,不再直接支持这种方式了,可以是可以使用,但是不推荐,具体使用可以参考《你必须掌握的EntityFramework 6.X与Core 2.0》一文。在这里我就详细的说下如何在EF core下实现。
首先就是实体类的建立:

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }

    public ICollection<PostTag> PostTags { get; } = new List<PostTag>();
}

public class Tag
{
    public int TagId { get; set; }
    public string Text { get; set; }

    public ICollection<PostTag> PostTags { get; } = new List<PostTag>();
}

public class PostTag
{
    public int PostId { get; set; }
    public Post Post { get; set; }

    public int TagId { get; set; }
    public Tag Tag { get; set; }
}

接下来就是映射了。派生自DbContext的上下文类:

public class MyContext : DbContext
{
    public DbSet<Post> Posts { get; set; }
    public DbSet<Tag> Tags { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<PostTag>().ToTable("PostTags");
        modelBuilder.Entity<PostTag>()
            .HasKey(t => new { t.PostId, t.TagId });
    }
}

这样就完成了我们的多对多映射了。我们只是通过多建立了一个表,将两个实体类的Id作为联合主键。

在Identity框架中,如果你细心点,你会发现有个userroles表,这个表是就是用来做Users表和Roles表的映射的。那么接下来我们只要新建一个实体类,随后在上下文类中映射到表:

modelBuilder.Entity<UserRoles>.ToTable("userroles");

这样就可以了。然后我们就可以很方便的给用户添加角色了。

参考链接:https://blog.oneunicorn.com/2017/09/25/many-to-many-relationships-in-ef-core-2-0-part-1-the-basics/

asp.net core下的如何给网站做安全设置

 

首先,我们来看下stack overflow网站的请求头文件:

可以看到一些我们熟悉或是陌生的HTTP头部文件字段。
在这里我们在对HTTP输入流的头部文件中,做一些基本的防护。首先要明确,既然我们是对HTTP头部做处理,那么就需要在Startup.cs类的 
Configuration方法中做处理,因为这里就是处理HTTP输入流的。

首先做一些基本的处理,比如中间件和基本的类:

1
2
3
4
5
6
7
8
public class SecurityHeadersPolicy 
{
    public IDictionary<stringstring> SetHeaders { get; }
         new Dictionary<stringstring>();
 
    public ISet<string> RemoveHeaders { get; }
        new HashSet<string>();
}

这里的头部信息是我们定义好的,用来增加或是删除头部信息,然后就是我们的中间件:

public class SecurityHeadersMiddleware
{
    private readonly RequestDelegate _next;
    private readonly SecurityHeadersPolicy _policy;

    public SecurityHeadersMiddleware(RequestDelegate next, SecurityHeadersPolicy policy)
    {
        _next = next;
        _policy = policy;
    }

    public async Task Invoke(HttpContext context)
    {
        IHeaderDictionary headers = context.Response.Headers;

        foreach (var headerValuePair in _policy.SetHeaders)
        {
            headers[headerValuePair.Key] = headerValuePair.Value;
        }

        foreach (var header in _policy.RemoveHeaders)
        {
            headers.Remove(header);
        }

       await _next(context);
    }
}

基于IApplicationBuilder接口做一个中间件的扩展方法:

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseSecurityHeadersMiddleware(this IApplicationBuilder app, SecurityHeadersBuilder builder)
    {
        SecurityHeaderPolicy policy = builder.Build();
        return app.UseMiddleware<SecurityHeadersMiddleware>(policy);
    }
}

封装好相关的安全类:

public class SecurityHeadersBuilder
{
    private readonly SecurityHeadersPolicy _policy = new SecurityHeadersPolicy();

    public SecurityHeadersBuilder AddDefaultSecurePolicy()
    {
        AddFrameOptionsDeny();
        AddXssProtectionBlock();
        AddContentTypeOptionsNoSniff();
        AddStrictTransportSecurityMaxAge();
        RemoveServerHeader();

        return this;
    }

    public SecurityHeadersBuilder AddFrameOptionsDeny()
    {
        _policy.SetHeaders[FrameOptionsConstants.Header] = FrameOptionsConstants.Deny;
        return this;
    }

    public SecurityHeadersBuilder AddFrameOptionsSameOrigin()
    {
        _policy.SetHeaders[FrameOptionsConstants.Header] = FrameOptionsConstants.SameOrigin;
        return this;
    }

    public SecurityHeadersBuilder AddFrameOptionsSameOrigin(string uri)
    {
        _policy.SetHeaders[FrameOptionsConstants.Header] = string.Format(FrameOptionsConstants.AllowFromUri, uri);
        return this;
    }

    public SecurityHeadersBuilder RemoveServerHeader()
    {
        _policy.RemoveHeaders.Add(ServerConstants.Header);
        return this;
    }

    public SecurityHeadersBuilder AddCustomHeader(string header, string value)
    {
        _policy.SetHeaders[header] = value;
        return this;
    }

    public SecurityHeadersBuilder RemoveHeader(string header)
    {
        _policy.RemoveHeaders.Add(header);
        return this;
    }

    public SecurityHeadersPolicy Build()
    {
        return _policy;
    }
}

最后注入到HTTP的输入流中:

app.UseSecurityHeadersMiddleware(new SecurityHeadersBuilder()
.AddDefaultSecurePolicy()
);

然后我们浏览一下网页,就可以在HTTP的头部信息中看到:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000
X-Powered-By: ASP.NET

还有一个就是CSRF的防护,如果之前你用过ASP.NET MVC,在最基本的MVC模板中,可能你会留意到已有的cshtml页面中的form表单有这么一句:

@Html.AntiForgeryToken()

这就是微软在MVC框架中为我们提供的防护CSRF的方法。我们在表单中直接使用上面那句代码就可以了,然后在表单提交的Action方法中:

[ValidateAntiForgeryToken]
[HttpPost]
public IActionResult AntiForm(string message)
{
return Content(message);
}

使用[ValidateAntiForgeryToken]属性,来验证CSRF。

参考链接:
How to add security headers in ASP.NET Core using custom middleware(如何使用自定义中间件在ASP.NET Core中添加安全标头)

初探CSRF在ASP.NET Core中的处理方式

代码地址:
https://github.com/RyanOvO/aspnetcore-fileup-demo

获取服务端https证书

最近开发一个需求,涉及获取服务端https证书。一般进行https调用我们都不太关心底层细节,直接使用WebClient或者HttpWebRequest来发送请求,这两种方法都无法获取证书信息,需要用到ServicePoint,这个类用于提供HTTP连接的管理。

写个Demo,拿新浪首页试一下:

using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;

namespace GetServerCertificateDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //用WebClient访问新浪首页
            var http = new WebClient();
            var uri = new Uri("https://www.sina.com.cn");
            http.DownloadString(uri);

            //通过Uri获取ServicePoint
            var servicePoint = ServicePointManager.FindServicePoint(uri);

            //取服务端证书,X509Certificate格式,转一下
            var serverCert = new X509Certificate2(servicePoint.Certificate);
            Console.WriteLine("颁发给:{0}", serverCert.Subject);
            Console.WriteLine("颁发者:{0}", serverCert.Issuer);
            Console.WriteLine("序列号:{0}", serverCert.SerialNumber);
            Console.WriteLine("指  纹:{0}", serverCert.Thumbprint);
            Console.WriteLine("起  始:{0}", serverCert.NotBefore);
            Console.WriteLine("过  期:{0}", serverCert.NotAfter);
        }
    }
}

运行看效果:

上半部分是程序运行结果,下面是用Firefox查看的服务端证书信息,各项信息都能对应上。如果程序中涉及多个不同服务器的访问也没关系,关键在于根据Uri获取ServicePoint,然后取到的证书就是此服务器的了。

Js异常捕获

 
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <script>
            function demo(){
                try{
                    alert(str);
                }catch(e){
                    alert(e);
                }
            }
            demo();
        </script>

        <form>
            <input id="txt" type="text"/>
            <input id="btn" type="button" onclick="demo1()" value="按钮" />
        </form>
        <script>
            function demo1(){
                try{
                    var e=document.getElementById("txt").value;
                if(e==""){
                    throw "请输入";
                }
                }catch(e){
                    alert(e);
                }

            }
        </script>
    </body>
</html>

js事件

onLoad    网页加载事件

onUnload    关闭网页事件

反射:获取Class对象的三种方式

数据库_mysql多表操作

数据库_mysql多表操作

 

多表操作

       实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系。

1.1    表与表之间的关系

l  一对多关系:

n  常见实例:客户和订单,分类和商品,部门和员工.

n  一对多建表原则:在从表(多方)创建一个字段,字段作为外键指向主表(一方)的主键.

l  多对多关系:

n  常见实例:学生和课程、用户和角色

n  多对多关系建表原则:需要创建第三张表,中间表中至少两个字段,这两个字段分别作为外键指向各自一方的主键.

l  一对一关系:(了解)

n  在实际的开发中应用不多.因为一对一可以创建成一张表.

n  两种建表原则:

u  外键唯一:主表的主键和从表的外键(唯一),形成主外键关系,外键唯一unique。

u  外键是主键:主表的主键和从表的主键,形成主外键关系。

1.2    外键约束

现在我们有两张表“分类表”和“商品表”,为了表明商品属于哪个分类,通常情况下,我们将在商品表上添加一列,用于存放分类cid的信息,此列称为:外键

此时“分类表category”称为:主表,“cid”我们称为主键。“商品表products”称为:从表,category_id称为外键。我们通过主表的主键和从表的外键来描述主外键关系,呈现就是一对多关系。

外键特点:

u  从表外键的值是对主表主键的引用。

u  从表外键类型,必须与主表主键类型一致。

l  声明外键约束     

语法:alter table 从表 add [constraint] [外键名称] foreign key (从表外键字段名) references 主表 (主表的主键);

[外键名称]用于删除外键约束的,一般建议“_fk”结尾

altertable 从表 drop foreignkey 外键名称

l  使用外键目的:

n  保证数据完整性

1.3    一对多操作

1.3.1    分析

  • category分类表,为一方,也就是主表,必须提供主键cid

  • products商品表,为多方,也就是从表,必须提供外键category_id

  • 1.3.2    实现:分类和商品

    ###创建分类表

    create table category(

    cidvarchar(32) PRIMARY KEY ,

    cnamevarchar(100)        #分类名称

    );

    # 商品表

    CREATE TABLE `products` (

    `pid`varchar(32) PRIMARY KEY  ,

    `name`VARCHAR(40) ,

    `price`DOUBLE

    );

    #添加外键字段

    alter table products add column category_id varchar(32);

    #添加约束

    alter table products add constraint product_fkforeign key (category_id) references category (cid);

    1.3.3    操作

    #1 向分类表中添加数据

    INSERT INTO category (cid ,cname) VALUES('c001','服装');

    #2 向商品表添加普通数据,没有外键数据,默认为null

    INSERT INTO products (pid,pname) VALUES('p001','商品名称');

    #3 向商品表添加普通数据,含有外键信息(数据存放在)

    INSERT INTO products (pid ,pname ,category_id)VALUES('p002','商品名称2','c001');

    #4 向商品表添加普通数据,含有外键信息(数据不存在) -- 不能异常

    INSERT INTO products (pid ,pname ,category_id)VALUES('p003','商品名称2','c999');

    #5 删除指定分类(分类被商品使用) -- 执行异常

    DELETE FROM category WHERE cid = 'c001';

    1.4    多对多

    1.4.1    分析

    • 商品和订单多对多关系,将拆分成两个一对多。

    • products商品表,为其中一个一对多的主表,需要提供主键pid

    • orders 订单表,为另一个一对多的主表,需要提供主键oid

    • orderitem中间表,为另外添加的第三张表,需要提供两个外键oid和pid

    1.4.2    实现:订单和商品

    ### 商品表[已存在]

    ### 订单表

    create table `orders`(

    `oid`varchar(32) PRIMARY KEY ,

    `totalprice` double   #总计

    );

    ### 订单项表

    create table orderitem(

    oidvarchar(50),-- 订单id

    pidvarchar(50)-- 商品id

    );

    ###---- 订单表和订单项表的主外键关系

    alter table `orderitem` add constraintorderitem_orders_fk foreign key (oid) references orders(oid);

    ###---- 商品表和订单项表的主外键关系

    alter table `orderitem` add constraintorderitem_product_fk foreign key (pid) references products(pid);

    ### 联合主键(可省略)

    alter table `orderitem` add primary key (oid,pid);

    1.4.3    操作

    #1 向商品表中添加数据

    INSERT INTO products (pid,pname) VALUES('p003','商品名称');

    #2 向订单表中添加数据

    INSERT INTO orders (oid ,totalprice)VALUES('x001','998');

    INSERT INTO orders (oid ,totalprice)VALUES('x002','100');

    #3向中间表添加数据(数据存在)

    INSERT INTO orderitem(pid,oid)VALUES('p001','x001');

    INSERT INTO orderitem(pid,oid)VALUES('p001','x002');

    INSERT INTO orderitem(pid,oid)VALUES('p002','x002');

    #4删除中间表的数据

    DELETE FROM orderitem WHERE pid='p002' AND oid ='x002';

    #5向中间表添加数据(数据不存在) -- 执行异常

    INSERT INTO orderitem(pid,oid)VALUES('p002','x003');

    #6删除商品表的数据 -- 执行异常

    DELETE FROM products WHERE pid = 'p001';

项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获的更多相关文章

  1. 基于Repository模式设计项目架构—你可以参考的项目架构设计

    关于Repository模式,直接百度查就可以了,其来源是<企业应用架构模式>.我们新建一个Infrastructure文件夹,这里就是基础设施部分,EF Core的上下文类以及Repos ...

  2. asp.net core下的如何给网站做安全设置

    首先,我们来看下stack overflow网站的请求头文件: 可以看到一些我们熟悉或是陌生的HTTP头部文件字段.在这里我们在对HTTP输入流的头部文件中,做一些基本的防护.首先要明确,既然我们是对 ...

  3. asp.net获取服务端和客户端信息

    asp.net获取服务端和客户端信息 获取服务器名:Page.Server.ManchineName获取用户信息:Page.User 获取客户端电脑名:Page.Request.UserHostNam ...

  4. 使用RSA加密在Python中逆向shell

    i春秋翻译小组-Neo(李皓伟) 使用RSA加密在Python中逆向shell 这是一个关于使用RSA加密编程逆向shell的python教程. 我想提一下,这篇文章更多的是关于理解shell中涉及的 ...

  5. 总结项目开发中用到的一些css\html技巧

    这篇就是用来总结记录的,会长期更新. 1,半透明背景效果(#ffffff颜色的半透明背景): font-style: italic;">#ffffff; filter:alpha(op ...

  6. php开发中怎么获取服务端MAC地址?

    MAC(Media Access Control或者Medium Access Control)地址,意译为媒体访问控制,或称为物理地址.硬件地址,用来定义网络设备的位置.在php中如何获取MAC(M ...

  7. 基于ASP.NET WPF技术及MVP模式实战太平人寿客户管理项目开发(Repository模式)

    亲爱的网友,我这里有套课程想和大家分享,假设对这个课程有兴趣的.能够加我的QQ2059055336和我联系.  课程背景 本课程是教授使用WPF.ADO.NET.MVVM技术来实现太平人寿保险有限公司 ...

  8. 使用Jquery+EasyUI 进行框架项目开发案例讲解之五 模块(菜单)管理源码分享

    http://www.cnblogs.com/huyong/p/3454012.html 使用Jquery+EasyUI 进行框架项目开发案例讲解之五  模块(菜单)管理源码分享    在上四篇文章 ...

  9. 使用Jquery+EasyUI 进行框架项目开发案例讲解之四 组织机构管理源码分享

    http://www.cnblogs.com/huyong/p/3404647.html 在上三篇文章  <使用Jquery+EasyUI进行框架项目开发案例讲解之一---员工管理源码分享> ...

随机推荐

  1. AJAX中的同步加载与异步加载

    AJAX是四个单词的简写,其中Asynchronous即异步的意思,异步的链接可以同时发起多个,并且不会阻止JS代码执行.与之对应的概念是同步,同步的链接在同一时刻只会有一个,并且会阻止后续JS代码的 ...

  2. Appium+python自动化22-Appium Desktop【转载】

    Appium Desktop 原滋原味的官方文档 Appium Desktop是一款用于Mac.Windows和Linux的开源应用,它提供了Appium自动化服务器在一个漂亮灵活的UI中的强大功能. ...

  3. python笔记-用python解决小学生数学题【转载】

    本篇转自博客:上海-悠悠 原文地址:http://www.cnblogs.com/yoyoketang/tag/python/ 前几天有人在群里给小编出了个数学题: 假设你有无限数量的邮票,面值分别为 ...

  4. vs2015 建立项目报错:值不能为空,参数名:path1的错误解决与“未将对象引用到对象的实例”

    “值不能为空,参数名:path1” 的错误.原因就是安卓sdk的路径不正确. 最简单的解决办法如下: 找到C:\Program Files (x86)\Android\android-sdk.进入文件 ...

  5. Python_Tips[6] -> is 和 == 的区别

    is和==的区别 / Difference between is and == 对于Python的对象来说,具有id/type/value三种特性,而在判断两个相等的is和==中,分别是对对象的id和 ...

  6. Cookie和Session在Node.JS中的实践(二)

    Cookie和Session在Node.JS中的实践(二) cookie篇在作者的上一篇文章Cookie和Session在Node.JS中的实践(一)已经是写得算是比较详细了,有兴趣可以翻看,这篇是s ...

  7. 替换Ubuntu默认的登录背景

    Ubuntu默认的登录背景看起来还是比较高贵的,但是作为一个爱折腾的人,当然要换成自己喜欢的背景图了.一开始跟着百度走,进了不少坑,最后还是自己走出来的.先上一个成品照 百度得到的答案几乎都是安装ub ...

  8. hdu 5206 Four Inages Strategy 计算几何

    题目链接:HDU - 5206 Young F found a secret record which inherited from ancient times in ancestral home b ...

  9. stack栈和Queue队列

    1.push将对象插入 System.Collections.Generic.Stack<T> 的顶部. Stack st = new Stack(); //栈是先进后出 st.Push( ...

  10. .xcodeprok cannot be opened because the project file cannot be parsed

    用svn更新代码后,打开xcode工程文件出现 xxx..xcodeproj cannot be opened because the project file cannot be parsed. 这 ...