WebApi
2020年2月15日
21:46
Restful语义风格
Get | 表示一个查询操作 |
---|---|
Post | 表示一个提交操作 |
Put | 表示先进行Get操作,如果得不到预期结果,则进行Post操作 |
Delete | 表示一个删除操作 |
Note:一般比较常用Get、Post,Put和Delete看情况<br /> <br /> <br /> <br />路由的配置<br />2020年3月13日<br />12:32<br /> <br /><br /> <br /> <br />Restful语义风格<br />2020年3月13日<br />12:20<br /> <br />定义api方法名称的约定,比如Get(int id)即表示是以HttpGet方式请求的WebApi方法,Post(string name)即表示是以HttpPost方式请求的WebApi方法。<br /> <br />具体如下:
Get | 表示一个查询操作 |
---|---|
Post | 表示一个提交操作 |
Put | 表示先进行Get操作,如果得不到预期结果,则进行Post操作 |
Delete | 表示一个删除操作 |
Note:一般比较常用Get、Post方式,Put和Delete比较少<br /> <br /><br /> <br /><br /> <br /> <br />跨域<br />2020年3月13日<br />12:40<br /> <br />为什么要跨域?<br />因为WebApi服务拒绝来自不同域名的ajax请求,注意仅ajax请求。<br /> <br />怎么跨域?<br />通过引入第三方包是最便捷的选择,Microsoft.AspNet.WebApi.Cors<br /> <br />1.引入架包;<br />2.启用跨域<br /><br /> <br />3.设置跨域的范围(如上图为整体跨域,如下图为控制器跨域)<br /><br /> <br /> <br /> <br /> <br /> <br /> <br />身份验证和状态持久<br />2020年3月13日<br />12:47<br /> <br />与Web不同,WebApi是无状态的,不存在如Session的概念,故它的状态持久必须额外通过一些手段处理。<br />一种方式是在每次请求的请求头中增加一个无法篡改的加密串,通过此加密串进行身份验证同时也能解析其中的数据作为持久数据。<br />即大致过程如下:<br />1.登录,服务器返回一个加密字符串,包含了必要的验证信息<br />2.客户端收到验证信息,保存(比如cookie或者本地其他方式)<br />3.再次发送请求时,请求头加上了验证信息<br />4.服务器收到了请求时,解析请求头,验证是否通过并且解析得到必要信息<br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br />操作总结<br />2020年3月13日<br />13:03<br /> <br />1.实际项目的路由规则最好不采用Restful,因为方法名可以作为重要的区分手段;<br />2.HttpGet和HttpPost的选择<br />(1)虽然查询一般是Get方法,但很多情况下是需要按一个动态变化的条件来执行查询的,在这种情况下当然使用对象的方式更好<br />(2)另一种比较常见的情况是提交,但参数很可能就是一个id或者简单类型的实参,这种情况以Get是不是也可以?<br />3.参数的封装和返回值的封装<br />有利于建立统一的处理逻辑,实现统一的请求和响应处理<br /> <br /> <br />LINQ TO SQL(DLINQ)<br />2020年1月4日<br />21:52<br /> <br />**概念:**<br />不论语言或框架,最终与数据库的交互都是通过ADO层,ADO层中进行的工作是高度相似的(1)连接数据库-执行-得到执行结果(2)执行结果映射实体对象或实体对象容器<br />LINQ TO SQL做的就是对这种简化,通过以下思路进行:<br />(1)定义映射关系,标识Mode与Table之间的关联,比如表名称,字段名称,主键等等,即System.Data.Linq.Mapping;<br />(2)执行映射关系、存储,即DataContext<br />(3)定义语法,执行增删改查,即LINQ<br /> <br />**映射关系**<br />以特性Attribute实现,在System.Data.Linq.Mapping中预先定义一些特性,比如<br />以Table特性标识对应的数据表名<br />以Column特性标识表中对象的字段属性,如名称、主键、类型、约束等等;<br /> [Table(Name = "sys_role")]<br /> public partial class SysRole<br /> {<br /> [Column(IsPrimaryKey = true)]<br /> public int id { get; set; }<br /> <br /> [Column]<br /> public string rolename { get; set; }<br /> <br /> [Column]<br /> public string roledesc { get; set; }<br /> }<br />具体实现未查,不作关系,肯定是通过特性实现一个通用逻辑(反射+特性)<br /> <br />**DataContext**<br />从构造函数上就可以看出来包括两个部分:<br />1.数据库连接,字符串或者连接类型都可以<br />2.映射关系,可以以特性标识或者自己建立<br /><br /> <br />通过DataContext.GetTable方法得到以Table类型作为容器的对象集合<br /> private void Frm_User_Load(object sender, EventArgs e)<br /> {<br /> //DataContext以字符串初始化<br /> //DataContext ctx = new DataContext(connectionString);<br /> //Table<SysUser> users = ctx.GetTable<SysUser>();<br /> <br /> //DataContext以数据库链接初始化<br /> IDbConnection conn = new SqlConnection(connectionString);<br /> DataContext ctx = new DataContext(conn);<br /> Table<SysUser> users = ctx.GetTable<SysUser>();<br /> }<br /> <br /> <br />当然不可能这样写,以强类型的上下文类进行封装<br /> public class UserContext : DataContext<br /> {<br /> public Table<SysUser> Users;<br /> <br /> public Table<SysRole> Roles;<br /> <br /> public Table<SysUserRole> UserRoles;<br /> <br /> public UserContext(IDbConnection connection) : base(connection) { }<br /> <br /> public UserContext(string connection) : base(connection) { }<br /> }<br /> <br />一个项目只需要一个强类型的上下文,还是每个大业务需要,按什么原则?<br /> <br />**DataContext执行**<br />执行仍旧是以ADO方法实现的,也就是Connection、Command等等,DataContext中也公开了这些。<br /> UserContext ctx = new UserContext(connectionString);<br /> <br /> var select = from c in ctx.Roles where c.rolename.Contains("管理") select c;<br /> DbCommand cmd = ctx.GetCommand(select);<br /> <br /> richTextBox1.Text += cmd.CommandText + Environment.NewLine;<br /> foreach (DbParameter parm in cmd.Parameters)<br /> {<br /> richTextBox1.Text += string.Format("参数名:{0},参数值:{1}<br/>", parm.ParameterName, parm.Value) + Environment.NewLine;<br /> }<br /> <br /> dataGridView1.DataSource = select;<br /> <br />LINQ自动的将对象的操作翻译,虽然能实现90%以上的TSQL功能。但是不可否认对于复杂的查询,使用TSQL能获得更好的效率,DataContext类型也提供了执行SQL语句的能力<br /> <br /> UserContext ctx = new UserContext(connectionString);<br /> <br /> //直接执行SQL命令<br /> ctx.ExecuteCommand("update sys_role set roledesc={0}", "Default");<br /> <br /> //直接执行SQL查询,疑问:查询得不到值?<br /> var result = ctx.ExecuteQuery<object>("select * from sys_role");<br /> //var result = ctx.ExecuteQuery<SysRole>("select * from sys_role");<br /> <br />增、删、改直接对Context的对象集合进行操作,再通过提交(SubmitChanges)方法执行<br /><br /> <br />对当前对象中集合的变化可以通过<br /><br /> IList<object> inserts = ctx.GetChangeSet().Inserts;<br /> IList<object> deletes = ctx.GetChangeSet().Deletes;<br /> IList<object> updates = ctx.GetChangeSet().Updates;<br /> <br />DataContext的日志<br />上面说到DataContext自动做了SQL的翻译工作,同时它将翻译的SQL记录在DataContext的Log属性中<br /><br /> <br />那么在外部可以对SQL日志进行记录<br /><br />日志的问题,什么时候写入,在程序设计中什么位置进行写入,需要额外考虑<br /> <br /> <br />EntityFramework<br />2019年12月4日<br />8:41<br /> <br />官方定义:“实体框架是一种对象关系映射器(O/RM),它使.NET开发人员能够通过.NET对象来操作数据库。它消除了开发人员通常需要编写的大多数数据访问代码的需求。“<br /> <br />实体框架工作在业务实体(域类)和数据库之间。**它保存实体属性中的数据到数据库,也可以从数据库中检索数据并自动将其转换为实体对象。**<br /> <br /><br /> <br />EF的组成简单总结如下:<br />**1、EDM(实体数据模型):** EDM包含三个主要部分——概念模型,映射和存储模型。<br />**概念模型(entity): **概念模型包含了模型类和它们之间的关系。 这将是独立于数据库表设计。<br />**存储模型(data):** 存储模型是数据库设计模型,包括表、视图、存储过程、以及它们之间的关系和钥匙。<br />**映射(mapping): **映射由概念模型如何映射到存储模型的信息组成。<br />**2、LINQ To Entity(L2E):** L2E是一种的查询实体对象的语言, 它返回在概念模型中定义的实体。 <br />**3、Entity SQL: **Entity SQL是一个类似于L2E的查询语言。 然而,它比L2E更加复杂。<br />**4、Object Services(对象服务):**对象服务是访问数据库中的数据并返回数据的主要入口点。它负责数据实例化,把**Entity Client Data Provider**(下一层)的数据转换成实体对象。<br />**5、Entity Client Data Provider:**主要职责是将L2E或Entity Sql转换成数据库可以识别的Sql查询语句,它通过**ADO.Net Data Provider**向数据库发送或者索取数据。<br />**6、ADO.Net Data Provider:**使用标准的Ado.net与数据库通信。<br /> <br /><br /> <br />EF的特性<br />1.**跨平台 **<br />EF Core是一个跨平台的框架,可以在Windows,Linux和Mac上运行。<br />2.**建模 **<br />EF可以创建具有不同数据类型get / set属性的EDM(Entity Data Model/实体数据模型)。它使用此模型查询或保存底层数据库的数据。<br />3.**查询 **<br />EF允许我们使用LINQ从底层数据库中检索数据,同时也支持直接对数据库执行原始SQL查询。<br />4.**更改跟踪 **<br />EF会跟踪需要提交到数据库的实体实例(属性值)发生的更改。<br />5.**保存 ** <br />EF调用SaveChanges()方法时,根据实体发生的更改,对数据库执行INSERT,UPDATE和DELETE命令。EF还提供了异步的SaveChangesAsync()方法。<br />6.**并发 **<br />默认情况下,从数据是从数据库中提取开始,EF使用乐观并发来避免我们做的修改被其他用户覆盖。<br />7.**事务 ** <br />EF在查询或保存数据时自动执行事务管理。它还提供自定义事务管理的选项。<br />8.**缓存 ** <br />EF包括开箱即用的第一级缓存。因此,重复查询将从缓存中返回数据,而不是访问数据库。<br />9.**配置** <br />EF允许我们使用注释属性配置EF模型,也可以使用Fluent API来覆盖默认约定。<br />10.**迁移 **<br />EF提供了一组迁移命令,我们可以在NuGet Package Manager控制台或命令行界面中执行这些命令来创建或管理底层数据库计划。<br /> <br />EF的发展过程<br />三个阶段:DBFirst==ModelFirst==CodeFirst,目前只需要考虑CodeFirst的这种方式,包括接下来的例子都是按照CodeFirst方式的。<br /> <br />以下内容主要参考博文:[https://www.cnblogs.com/lsxqw2004/p/4701979.html](https://www.cnblogs.com/lsxqw2004/p/4701979.html)<br /> <br /> <br /> <br /> <br />AutoFac<br />2020年1月23日<br />15:57<br /> <br />**Autofac 中文文档 **[https://autofaccn.readthedocs.io/zh/latest/index.html](https://autofaccn.readthedocs.io/zh/latest/index.html)<br /> <br />严重性 代码 说明 项目 文件 行 禁止显示状态<br />错误 无法安装程序包“Microsoft.Extensions.Configuration.Json 3.1.1”。你正在尝试将此程序包安装到目标为“.NETFramework,Version=v4.6.1”的项目中,但该程序包不包含任何与该框架兼容的程序集引用或内容文件。有关详细信息,请联系程序包作者。 0 <br /> <br /> <br />MVC<br />2019年12月4日<br />8:42<br /> <br /> <br /> <br /> <br /> <br />表达式(Expression)<br />2020年3月25日<br />21:19<br /> <br />[https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.expression?view=netframework-4.8](https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.expression?view=netframework-4.8)<br /> <br /><br /> <br /> <br />下面是平常使用最多的表达式<br />ConstantExpression:常量表达式<br />ParameterExpression:参数表达式<br />UnaryExpression:一元运算符表达式<br />BinaryExpression:二元运算符表达式<br />TypeBinaryExpression:is运算符表达式<br />ConditionalExpression:条件表达式<br />MemberExpression:访问字段或属性表达式<br />MethodCallExpression:调用成员函数表达式<br />Expression<TDelegate>:委托表达式<br /> <br />来自 <[_https://www.cnblogs.com/snailblog/p/11521043.html_](https://www.cnblogs.com/snailblog/p/11521043.html)><br /> <br /> <br /> <br /> <br /> <br />表达式树和表达式里面的类型NodeType是一个枚举,一共有85个类型,有兴趣的朋友可以去了解下。<br />常用的类型如下:<br />ExpressionType.And:C#中类似于&<br />ExpressionType.AndAlso:C#中类似于&&<br />ExpressionType.Or:C#中类似于|<br />ExpressionType.OrElse:C#中类似于||<br />ExpressionType.Equal:C#中类似于==<br />ExpressionType.NotEqual:C#中类似于!=<br />ExpressionType.GreaterThan:C#中类似于><br />ExpressionType.GreaterThanOrEqual:C#中类似于>=<br />ExpressionType.LessThan:C#中类似于<<br />ExpressionType.LessThanOrEqual:C#中类似于<=<br />ExpressionType.Add:C#中类似于+<br />ExpressionType.AddChecked:C#中类似于+<br />ExpressionType.Subtract:C#中类似于-<br />ExpressionType.SubtractChecked:C#中类似于-<br />ExpressionType.Divide:C#中类似于/<br />ExpressionType.Multiply:C#中类似于*<br />ExpressionType.MultiplyChecked:C#中类似于*<br /> <br />来自 <[_https://www.cnblogs.com/snailblog/p/11521043.html_](https://www.cnblogs.com/snailblog/p/11521043.html)><br /> <br /> <br /> <br /> <br /> <br />Dapper<br />2020年4月13日<br />9:37<br /> <br />**Dapper**<br />**简述:**<br />Dapper是一个轻量的ORM,主要是对ADO层做的封装,以Emit反射进行对象反序列化。<br />和EF比较起来,功能是不足的。<br />性能是很好的,可以作为ADO的替代。全部的操作都以SQL语句为基础,不能实现对象的动态跟踪。<br />Git:[https://github.com/StackExchange/Dapper](https://github.com/StackExchange/Dapper)<br />**2020-4-13**<br />**初步熟悉**<br />1.基于IDbConnection的一系列扩展方法,核心SqlMapper.cs,可以简单的理解为对ADO执行和对结果集转换为对象的操作。<br />2.在MSSQL操作上的性能几乎一致,不必考虑。比较耗时的是对象处理,这块需要再花时间了解。<br />3.虽然Dapper自动管理数据库连接,但要注意几点问题<br />//短短三行代码即实现了dapper连接的主动管理和自动管理<br />bool wasClosed = cnn.State == ConnectionState.Closed;//判断连接是否为关闭状态<br />...<br />if (wasClosed) cnn.Open();<br />...<br />if (wasClosed) cnn.Close();<br />(1)超过连接池最大连接数,一直自动管理或手动管理可以避免,手动管理注意close<br />(2)尤其是在事务处理时,因为事务要求连接打开,要在finally块进行close<br />//注意:BeginTransaction要求连接是Open状态,否则错误:无效操作。连接被关闭<br />IDbTransaction transaction = connection.BeginTransaction();<br />**4.下面以同步方法为例,但实际是支持异步方法的**<br />**CRUD**<br />**函数定义**<br />/// <summary>Execute parameterized SQL.</summary><br />/// <param name="cnn">The connection to query on.</param><br />/// <param name="sql">The SQL to execute for this query.</param><br />/// <param name="param">The parameters to use for this query.</param><br />/// <param name="transaction">The transaction to use for this query.</param><br />/// <param name="commandTimeout">Number of seconds before command execution timeout.</param><br />/// <param name="commandType">Is it a stored proc or a batch?</param><br />/// <returns>The number of rows affected.</returns><br />public static int Execute(<br /> this IDbConnection cnn,<br /> string sql,<br /> object param = null,<br /> IDbTransaction transaction = null,<br /> int? commandTimeout = null,<br /> CommandType? commandType = null)<br />{<br /> CommandDefinition command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered, new CancellationToken());<br /> return cnn.ExecuteImpl(ref command);<br />}<br />**实例**<br />string sqlCommandText = @"INSERT INTO CICUser(Username,PasswordHash)VALUES(<br /> @UserName,@Password<br /> )";<br />using (IDbConnection connection = new SqlConnection(DbHelper.Connection))<br />{<br /> int result = 0;
//实例对象
result = connection.Execute(sqlCommandText, new User
{
UserName = “jack”,
Password = “jack”,
});
Console.WriteLine(result > 0 ? “Success” : “Error”);
//匿名对象
result = connection.Execute(sqlCommandText, new { UserName = “Paul”, Password = “Paul” });
Console.WriteLine(result > 0 ? “Success” : “Error”);
//字典 DynamicParameters是Dapper对字典的一个封装类型
DynamicParameters dynamicParameters = new DynamicParameters();
dynamicParameters.Add(“UserName”, “Chris”);
dynamicParameters.Add(“Password”, “Chris”);
result = connection.Execute(sqlCommandText, dynamicParameters);
Console.WriteLine(result > 0 ? “Success” : “Error”);
//集合 Dapper自动进行了迭代
var list = Enumerable.Range(0, 10).Select(i => new User()
{
UserName = “User” + i,
Password = “User” + i
});
result = connection.Execute(sqlCommandText, list);
Console.WriteLine(result > 0 ? “Success” : “Error”);
}
string sqlCommandText = @”UPDATE CICUser SET Email=@Email WHERE UserName=@UserName”;
using (IDbConnection connection = new SqlConnection(DbHelper.Connection))
{
int result = 0;
//实例对象
result = connection.Execute(sqlCommandText, new User
{
UserName = “jack”,
Email = “jack.com”
});
Console.WriteLine(result > 0 ? “Success” : “Error”);
//匿名对象
result = connection.Execute(sqlCommandText, new { UserName = “Paul”, Email = “Paul.com” });
Console.WriteLine(result > 0 ? “Success” : “Error”);
//字典 DynamicParameters是Dapper对字典的一个封装类型
DynamicParameters dynamicParameters = new DynamicParameters();
dynamicParameters.Add(“UserName”, “Chris”);
dynamicParameters.Add(“Email”, “Chris.com”);
result = connection.Execute(sqlCommandText, dynamicParameters);
Console.WriteLine(result > 0 ? “Success” : “Error”);
//集合 Dapper自动进行了迭代
var list = Enumerable.Range(0, 10).Select(i => new User()
{
UserName = “User” + i,
Email = “User” + i + “.com”
});
result = connection.Execute(sqlCommandText, list);
Console.WriteLine(result > 0 ? “Success” : “Error”);
}
string sqlCommandText = @”SELECT * FROM CICUser WHERE UserName in @Names”;
using (IDbConnection connection = new SqlConnection(DbHelper.Connection))
{
var list = connection.Query
list.ForEach(item => Console.WriteLine($”UserName:{item.UserName}——Password:” + item.Password));
}
参数解析
1.可传递的参数类型一般是对象(实例或匿名),字典,对象集合(**List、Array)
2.若传递的是对象集合,则Dapper在内部进行了隐式迭代,不需要再写循环!
条件子句
1.In子句在sql中不再需要’()‘
CRUD之事务**
string sqlCommandText = @”INSERT INTO CICUser(Username,PasswordHash)VALUES(
@UserName,@Password
)”;
using (IDbConnection connection = new SqlConnection(DbHelper.Connection))
{
int result = 0;
connection.Open();
//注意:BeginTransaction要求连接是Open状态,否则错误:无效操作。连接被关闭
IDbTransaction transaction = connection.BeginTransaction();
//集合 Dapper自动进行了迭代
var list = Enumerable.Range(0, 10).Select(i => new User()
{
UserName = “User” + i,
Password = “User” + i
});
try
{
Enumerable.Range(0, 10).AsList().ForEach(i =>
{
connection.Execute(sqlCommandText, new User()
{
UserName = “User” + i,
Password = “User” + i
}, transaction);
});
transaction.Commit();<br /> }<br /> catch<br /> {<br /> transaction.Rollback();<br /> }<br />}<br />**CRUD之查询进阶**<br />**函数定义**<br /> /// <summary><br /> /// Perform a multi-mapping query with 2 input types.<br /> /// This returns a single type, combined from the raw types via <paramref name="map" />.<br /> /// </summary><br /> /// <typeparam name="TFirst">The first type in the recordset.</typeparam><br /> /// <typeparam name="TSecond">The second type in the recordset.</typeparam><br /> /// <typeparam name="TReturn">The combined type to return.</typeparam><br /> /// <param name="cnn">The connection to query on.</param><br /> /// <param name="sql">The SQL to execute for this query.</param><br /> /// <param name="map">The function to map row types to the return type.</param><br /> /// <param name="param">The parameters to use for this query.</param><br /> /// <param name="transaction">The transaction to use for this query.</param><br /> /// <param name="buffered">Whether to buffer the results in memory.</param><br /> /// <param name="splitOn">The field we should split and read the second object from (default: "Id").</param><br /> /// <param name="commandTimeout">Number of seconds before command execution timeout.</param><br /> /// <param name="commandType">Is it a stored proc or a batch?</param><br /> /// <returns>An enumerable of <typeparamref name="TReturn" />.</returns><br /> public static IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(<br /> this IDbConnection cnn,<br /> string sql,<br /> Func<TFirst, TSecond, TReturn> map,<br /> object param = null,<br /> IDbTransaction transaction = null,<br /> bool buffered = true,<br /> string splitOn = "Id",<br /> int? commandTimeout = null,<br /> CommandType? commandType = null)<br /> {<br /> return cnn.MultiMap<TFirst, TSecond, SqlMapper.DontMap, SqlMapper.DontMap, SqlMapper.DontMap, SqlMapper.DontMap, SqlMapper.DontMap, TReturn>(sql, (Delegate) map, param, transaction, buffered, splitOn, commandTimeout, commandType);<br /> }<br />参数解析:<br />1.map<br />委托,从源类型输出新类型的方法<br />2.splitOn<br />一个字符串,表示的是区分两个对象中的起始字段,默认是id。<br />比如A表(id,name,phone) 、B表(id,grade,class),传入“id”这样就可以区分好哪些字段是哪些表的,以供对象反序列化<br />**1对1查询实例**<br />string sqlCommandText = @"SELECT c.UserId,<br />c.Username AS UserName,<br /> c.PasswordHash AS [Password],<br /> c.Email,<br /> c.PhoneNumber,<br /> c.IsFirstTimeLogin,<br /> c.AccessFailedCount,<br /> c.CreationDate,<br /> c.IsActive,<br /> r.RoleId,<br /> r.RoleName<br /> FROM dbo.CICUser c<br /> INNER JOIN CICUserRole cr ON cr.UserId = c.UserId<br /> INNER JOIN CICRole r ON r.RoleId = cr.RoleId";
using (IDbConnection connection = new SqlConnection(DbHelper.Connection))
{
var list = connection.Query
(user, role) =>
{
user.Role = role;
return user;
},
null,
null,
true,
“RoleId”,
null,
null).ToList();
list.ForEach(item => Console.WriteLine($”UserName:{item.UserName}——RoleName:” + item.Role.RoleName));
}
1对多查询实例
string sqlCommandText = @”SELECT c.UserId,
c.Username AS UserName,
c.PasswordHash AS [Password],
c.Email,
c.PhoneNumber,
c.IsFirstTimeLogin,
c.AccessFailedCount,
c.CreationDate,
c.IsActive,
r.RoleId,
r.RoleName
FROM dbo.CICUser c
INNER JOIN CICUserRole cr ON cr.UserId = c.UserId
INNER JOIN CICRole r ON r.RoleId = cr.RoleId”;
using (IDbConnection connection = new SqlConnection(DbHelper.Connection))
{
var lookUp = new Dictionary
var list = connection.Query
(user, role) =>
{
User u;
if (!lookUp.TryGetValue(user.UserId, out u))
{
lookUp.Add(user.UserId, u = user);
}
u.Role.Add(role);<br /> return user;<br /> }, null, null, true, "RoleId", null, null).ToList();<br /> var result = lookUp.Values;
list.ForEach(item =>
Console.WriteLine($”UserName:{item.UserName}——RoleName:” +
string.Join(“,”, item.Role.Select(p => p.RoleName))));
}
批量查询-看看就可以了
var sql = @”select from CICUser where UserID = @UserID;
select from CICRole where RoleID = @RoleID”;
using (IDbConnection connection = new SqlConnection(DbHelper.Connection))
{
using (var multi = connection.QueryMultiple(sql, new
{
UserID = 43,
RoleID = 1
}))
{
var m1 = multi.Read
var m2 = multi.Read
}
}
查询注意点
using (IDbConnection connection = new SqlConnection(DbHelper.Connection))
{
connection.QueryFirstOrDefault
connection.QueryFirstOrDefault
connection.Query
connection.Query
}