标题说明了一切,我试图使用它,但我不理解它。由于我是一名业余爱好者,问题可能是缺乏知识,但我已经阅读了十几个关于这件事的问题并且用谷歌搜索了三天,我仍然没有&#39理解它。
我有很多问题,我不确定我是否应该只在一个问题中写出所有问题,或者即使有人会全部阅读。如果有人有其他解决方案或认为我应该将其分解为不同的问题......好吧,我愿意接受建议。
我打算写一个例子,但是我再次读了十几个例子并没有帮助我。
我无法理解如何像github上的例子一样工作:
var sql =
@"select * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id";
var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post;});
因此,Post
具有User
类型的属性,该属性称为Owner
,对吧?类似的东西:
public class Post
{
...
public User Owner { get; set;}
}
因此,Query<Post, User, Post>
将返回包含所有属性的Post
实例,而不是,AND将创建User
实例并将其分配给Post.Owner
属性?如何将简单参数添加到该查询中,例如,如果有人想将id作为int
参数传递给...WHERE Id = @Id", new {Id = id}
,那么参数应该添加到哪里,因为参数现在是{{1 }}?参数总是指给定的类型,你只能使用简单的典型参数进行动态查询,两者是否可以同时使用?怎么样?
另外,如何区分DB字段到什么对象?它会使类名= DB表名?如果这些类与DB表的名称不同,并且我想使用(post, user) => { post.Owner = user; return post;}
attribte,它是否有效,或者该属性仅适用于[Table]
方法,会发生什么?它可以与共享相同数据库表的对象一起使用吗?
关于不同对象问题的同一表,f.i。假设我有一个Dapper.Contrib.Extensions
对象,其中包含Person
个对象:
BankAccount
我可以将字符串帐户存储在与public class Person
{
...
public BankAccount Account {get; set;}
...
}
public class BankAccount
{
private string _Account;
public string Account
{
get { return _Account; }
set
{
if(!CheckIfIBANIsCorrect(value))
throw new Exception();
_Account = value;
}
}
private bool CheckIfIBANIsCorrect(string IBAN)
{
//...
//Check it
}
}
相同的表中,因为每个人都有一个由该人ID引用的帐户。我应该如何映射这样的东西?有没有办法,如果我只是简单地将结果加载到动态对象中然后创建所有对象,Person
将创建Query
对象的其余部分,我应该自己创建嵌套对象?
顺便说一句,Person
如何被用于所有这些?我知道它应该将结果分成各种各样的&#34;组&#34;所以你可以用Ids f.i分割结果。并采取你所需要的,但我不明白我应该如何从不同的&#34;组&#34;中检索信息,以及它如何返回不同的&#34;组&#34;,列表,枚举什么?。
splitOn
除了我的理解之外还有其他的东西,我读过多少问题和答案。
你知道...... * QueryMultiple
的工作原理是什么的?我在这里阅读或谷歌搜索假设.Read
是某种自动化的东西,可以奇迹般地辨别对象之间。再次,它是否按类名划分结果,所以我只需要确保每个对象都有正确的表名?在这种情况下,Read
属性又会发生什么?
我认为我遇到的问题是我无法找到(我认为它不存在)一个描述所有内容的网页(GitHub上的示例非常缺乏)而且我仍然只能找到具体案例的答案,这些答案并不能完全回答我试图理解的内容,而只是那些具体的案例,这些案例在我阅读时越来越让我感到困惑,因为每个人似乎都在使用一堆不同的方法,没有解释为什么或如何。
答案 0 :(得分:1)
我认为Dapper查询连接表查询的主要问题是认为列表中的第二个参数始终是“param”参数。请考虑以下代码:
var productsWithoutCategories = conn.Query<Product>(
"SELECT * FROM Products WHERE ProductName LIKE @nameStartsWith + '%'",
new { nameStartsWith = "a" }
);
这里有两个参数“sql”和“param” - 如果我们使用命名参数,那么代码将如下所示:
var productsWithoutCategories = conn.Query<Product>(
sql: "SELECT * FROM Products WHERE ProductName LIKE @nameStartsWith + '%'",
param: new { nameStartsWith = "a" }
);
在您的示例中,您有
var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post;});
第二个参数实际上是一个名为“map”的参数,它告诉Dapper如何在SQL查询中加入两个表的情况下组合实体。如果我们使用命名参数,那么它将如下所示:
var data = connection.Query<Post, User, Post>(
sql: sql,
map: (post, user) => { post.Owner = user; return post;}
);
我将在一个完整的示例中使用类NORTHWND数据库。假设我们有课程
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public bool Discontinued { get; set; }
public Category Category { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
}
我们要构建一个Products列表,并填充嵌套的Category类型,我们将执行以下操作:
using (var conn = new SqlConnection("Server=.;Database=NORTHWND;Trusted_Connection=True;"))
{
var productsWithCategories = conn.Query<Product, Category, Product>(
"SELECT * FROM Products INNER JOIN Categories ON Categories.CategoryID = Products.CategoryID,
map: (product, category) =>
{
product.Category = category;
return product;
},
splitOn: "CategoryID"
);
}
这会遍历JOIN'd产品和类别数据的所有行,并生成一个独特的产品列表,但不能确定如何将类别数据与它组合,因此它需要一个“地图”功能,它需要一个产品实例和一个Category实例,必须返回一个Product实例,该实例具有与之相结合的Category数据。在这个例子中,它很简单 - 我们只需要将Product实例上的Category属性设置为Category实例。
请注意,我必须指定“splitOn”值。 Dapper假定表的关键列将简称为“Id”,如果是,则它可以自动处理这些列上的连接。但是,在这种情况下,我们正在加入一个名为“CategoryID”的列,因此我们必须告诉Dapper根据该列名将数据拆分(分为产品和分类)。
如果我们还想指定“param”对象来过滤结果,那么我们可以执行以下操作:
var productsWithCategories = conn.Query<Product, Category, Product>(
"SELECT * FROM Products INNER JOIN Categories ON Categories.CategoryID = Products.CategoryID WHERE ProductName LIKE @nameStartsWith + '%'",
map: (product, category) =>
{
product.Category = category;
return product;
},
param: new { nameStartsWith = "a" },
splitOn: "CategoryID"
);
为了回答您的最后一个问题,QueryMultiple只需一次执行多个查询,然后允许您单独阅读它们。例如,而不是这样做(使用两个单独的查询):
using (var conn = new SqlConnection("Server=.;Database=NORTHWND;Trusted_Connection=True;"))
{
var categories = conn.Query("SELECT * FROM Categories");
var products = conn.Query("SELECT * FROM Products");
}
您可以在一个批处理中指定一个包含两个查询的SQL语句,但是您需要从QueryMultiple返回的组合结果集中单独读取它们:
using (var conn = new SqlConnection("Server=.;Database=NORTHWND;Trusted_Connection=True;"))
{
var combinedResults = conn.QueryMultiple("SELECT * FROM Categories; SELECT * FROM Products");
var categories = combinedResults.Read<Category>();
var products = combinedResults.Read<Product>();
}
我认为我在QueryMultiple中看到的其他示例有点令人困惑,因为它们经常从每个查询返回单个值,而不是完整的行集(这在简单的Query调用中更常见)。所以希望上面的内容能为你解决这个问题。
注意:我没有提及你关于[表格]属性的问题 - 如果你在尝试完之后仍然遇到问题,那么我会建议为它创建一个新问题。 Dapper使用“splitOn”值来确定一个实体的列何时结束和下一个开始(在上面的JOIN示例中,有Product的字段,然后是Category的字段)。如果你将Category类重命名为其他类,那么查询仍然有效,在这种情况下Dapper不依赖于表名 - 所以希望你根本不需要[Table]。