我正在尝试使用Dapper与ASP.NET SQL Membership Provider表进行交互.我包装了SqlMembershipProvider类并添加了一个额外的方法来获取MembershipUsers给出一些与我的一些自定义表相关的标准.
使用Dapper查询数据时,似乎Dapper首先使用无参数构造函数实例化该类,然后将返回的列"映射"到对象的属性中.
但是,MembershipUser类上的UserName属性没有setter.从Dapper SqlMapper.cs中的第1417行开始,该方法GetSettableProps()只获得可设置的属性.
我试图做一个MultiMap查询来调用构造函数,但问题是传递给查询的对象已经缺少UserName.
我猜我可以修改GetSettableProps()方法,但我不确定这是否有效,或者它是否会影响我现有的代码.
反正我是否要调用MembershipUser类具有的自定义构造函数?
或者我是否可以对Dapper做出合理的改变以支持我的情况?
**更新**
Marc使用非泛型/动态Query()方法的答案是正确的,但对后人来说,这是我在Dapper中引用的方法:
static List<PropInfo> GetSettableProps(Type t)
{
return t
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Select(p => new PropInfo
{
Name = p.Name,
Setter = p.DeclaringType == t ? p.GetSetMethod(true) : p.DeclaringType.GetProperty(p.Name).GetSetMethod(true),
Type = p.PropertyType
})
.Where(info => info.Setter != null)
.ToList();
}
Run Code Online (Sandbox Code Playgroud) 我已经成功地将今天的东西作为小沙箱/ POC项目运行起来,但似乎在一个问题上让我头疼...
题:
有没有办法让dapper映射到带有空格的SQL列名.
作为我的结果集,我有一些这样的效果.
例如:
SELECT 001 AS [Col 1],
901 AS [Col 2],
00454345345345435349 AS [Col 3],
03453453453454353458 AS [Col 4]
FROM [Some Schema].[Some Table]
Run Code Online (Sandbox Code Playgroud)
我的班级看起来像这样
public class ClassA
{
public string Col1 { get; set; }
public string Col2 { get; set; }
///... etc
}
Run Code Online (Sandbox Code Playgroud)
我的实现目前看起来像这样
public Tuple<IList<TClass>, IList<TClass2>> QueryMultiple<TClass, TClass2>(object parameters)
{
List<TClass> output1;
List<TClass2> output2;
using (var data = this.Connection.QueryMultiple(this.GlobalParameter.RpcProcedureName, parameters, CommandType.StoredProcedure))
{
output1 = data.Read<TClass>().ToList();
output2 = data.Read<TClass2>().ToList();
}
var result = new …Run Code Online (Sandbox Code Playgroud) 我有一个字符串数组,我想要一个包含IN子句的查询,如:
"... WHERE t.name IN ('foo', 'bar', 'baz')..>"
Run Code Online (Sandbox Code Playgroud)
这是我的查询的最后一位,其中包含"where in X in"子句:
...
left join genre_tag_band_join tj on hb.id = tj.band_id or ob.id = tj.band_id
left join genre_tags t on tj.genre_tag_id = t.id
inner join venues v on e.venue_id = v.id
where t.name IN @tagsParam...
Run Code Online (Sandbox Code Playgroud)
我像这样做一个Dapper电话
var shows = con.Query<Event, Band, Band, GenreTag, Venue, Event>(query, (e, hb, ob, gt, v) =>
{
Event show;
...
return e;
},
new { tagsParam = tagsArr}).AsQueryable();
Run Code Online (Sandbox Code Playgroud)
其中tagsArr是一个字符串[].
我得到例外:
{"42601:语法错误位于或附近\"$ 1 \""}
和Dapper一起玩,我对目前的结果非常满意 - 很有趣!
但现在,我的下一个场景是从两个表中读取数据 - a Student和Address表.
Student表有一个主键StudentID (INT IDENTITY),Address有一个AddressID (INT IDENTITY).Student还有一个名为AddressID链接到Address表中的FK .
我的想法是创建两个类,每个表一个,具有我感兴趣的属性.另外,我在C#中将PrimaryAddress类型的属性Address放到我的Student类中.
然后我尝试在单个查询中检索学生和地址数据 - 我模仿Github页面上给出的样本:
var data = connection.Query<Post, User>(sql, (post, user) => { post.Owner = user; });
var post = data.First();
Run Code Online (Sandbox Code Playgroud)
在这里,检索a Post和a User,并将帖子的所有者设置为用户 - 返回的类型是Post- 正确吗?
所以在我的代码中,我为通用Query扩展方法定义了两个参数- Student作为第一个应该返回的参数,Address第二个参数将存储到学生实例中:
var student = _conn.Query<Student, Address> …Run Code Online (Sandbox Code Playgroud) 我在dapper试图拆分包含的列时出现MultiMaps问题NULL.Dapper似乎没有实例化对象,我的映射函数接收null而不是对象.
这是我的新测试:
class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Category Category { get; set; }
}
class Category
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public void TestMultiMapWithSplitWithNullValue()
{
var sql = @"select 1 as id, 'abc' as name, NULL as description, 'def' as name";
var product = connection.Query<Product, …Run Code Online (Sandbox Code Playgroud) 我有一个存储过程InsertCars,它接受用户定义的表类型列表CarType.
CREATE TYPE dbo.CarType
AS TABLE
(
CARID int null,
CARNAME varchar(800) not null,
);
CREATE PROCEDURE dbo.InsertCars
@Cars AS CarType READONLY
AS
-- RETURN COUNT OF INSERTED ROWS
END
Run Code Online (Sandbox Code Playgroud)
我需要从Dapper调用这个存储过程.我用Google搜索并找到了一些解决方案.
var param = new DynamicParameters(new{CARID= 66, CARNAME= "Volvo"});
var result = con.Query("InsertCars", param, commandType: CommandType.StoredProcedure);
Run Code Online (Sandbox Code Playgroud)
但是我收到一个错误:
过程或函数InsertCars指定了太多参数
存储过程也InsertCars返回插入行的计数; 我需要得到这个值.
问题的根源在哪里?
我的问题是我在通用列表中有汽车List<Car> Cars,我希望将此列表传递给存储过程.它优雅的方式存在怎么办?
public class Car
{
public CarId { get; set; }
public CarName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
谢谢你的帮助
EDITED …
所以我有一种情况,我必须加入(并映射)超过7个实体(据我所知,这是Dapper的当前限制).这是我到目前为止(伪代码):
using (var connection = new SqlConnection(_connectionString)) {
IEnumerable<BigEntity> results =
connection.Query<BigEntity, Lookup1, Lookup2, ... around 10 of them>(sql,
(b, l1, l2, l3) => {
// map and return here
},
splitOn: "split1, split2 ...");
}
Run Code Online (Sandbox Code Playgroud)
这种限制有什么办法吗?以前有人面对这个吗?也许一些Dapper扩展?
我有一个过程,它接受一个表值参数,以及其他:
CREATE PROCEDURE [dbo].[Update_Records]
@currentYear INT,
@country INT,
@records Record_Table_Type READONLY
AS
Run Code Online (Sandbox Code Playgroud)
我试图用Dapper.TVP来称呼它.
这是我到目前为止的代码:
var recordsParameter = new List<SqlDataRecord>();
// This metadata matches 'Record_Table_Type' in the Database
var recordsMetaData = new[]
{
new SqlMetaData("OriginalValue", SqlDbType.Decimal, 19, 4),
new SqlMetaData("NewValue", SqlDbType.Decimal, 19, 4),
new SqlMetaData("NewPercent", SqlDbType.Decimal, 7, 2),
};
foreach (var r in records)
{
var record = new SqlDataRecord(recordsMetaData);
record.SetDecimal(0, r.OriginalValue);
record.SetDecimal(1, r.NewValue);
record.SetDecimal(2, r.NewPercent);
recordsParameter.Add(record);
}
var spParams = new DynamicParameters(new
{
currentYear = filter.currentYear,
country = filter.country,
}); …Run Code Online (Sandbox Code Playgroud) 我正在使用.net核心和dapper,第一个没有DataTables,第二个使用它们用于TVP.
我试图将a转换List<T>为a List<SqlDataRecord>,使用此列表创建一个SqlParameter然后将其转换为DynamicParameter但遗憾的是我得到了:The member of type Microsoft.SqlServer.Server.SqlDataRecord cannot be used as a parameter value
玩了一下之后IDynamicParameters,我就开始了.
扩展方法 IEnumerable
public static DynamicWrapper toTVP<T>(this IEnumerable<T> enumerable, string tableName, string typeName)
{
List<SqlDataRecord> records = new List<SqlDataRecord>();
var properties = typeof(T).GetProperties().Where(p => Mapper.TypeToSQLMap.ContainsKey(p.PropertyType));
var definitions = properties.Select(p => Mapper.TypeToMetaData(p.Name, p.PropertyType)).ToArray();
foreach (var item in enumerable)
{
var values = properties.Select(p => p.GetValue(item, null)).ToArray();
var schema = new SqlDataRecord(definitions);
schema.SetValues(values);
records.Add(schema);
}
SqlParameter result = new SqlParameter(tableName, SqlDbType.Structured); …Run Code Online (Sandbox Code Playgroud) UPDATE
我永远无法使用"Windows身份验证"(域)用户进行此操作.但是使用"SQL Server身份验证"用户,一切都像它应该的那样工作.
原始问题
我的connectionString: Server=ip;Database=dbname;User Id=xxx\user;Password=pass;
连接字符串位于appsettings.json中,如下所示:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"ConnectionString": "Server=ip;Database=dbname;User Id=xxx\user;Password=pass;"
}
}
Run Code Online (Sandbox Code Playgroud)
然后我将它传递给"Startup.cs"文件中的静态类,如下所示:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
Orm.DatabaseConnection.ConnectionString = Configuration["ConnectionStrings:ConnectionString"];
}
Run Code Online (Sandbox Code Playgroud)
这是我发起连接的地方:
using System.Data.SqlClient;
namespace MyProject.Orm
{
public static class DatabaseConnection
{
public static string ConnectionString { get; set; }
public static SqlConnection ConnectionFactory()
{
return new SqlConnection(ConnectionString);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的控制器:
public string Get()
{
using (var databaseConnection = …Run Code Online (Sandbox Code Playgroud) sql-server sql-server-2008 dapper .net-core asp.net-core-2.0
dapper ×10
c# ×7
sql-server ×3
.net-core ×2
reflection ×2
asp.net-mvc ×1
npgsql ×1
postgresql ×1
sql ×1