不使用 Dapper.Rainbow
Dapper.Rainbow 在其当前形式下是不可能的,但 my pull request in github 使这成为可能。
我很惊讶没有人建议使用Dapper.Contrib。我知道我问过该功能是否在 Rainbow 中。但没想到没人会注意到这句话(尤其是粗体字):
现在我正在寻找可以更容易做到的东西
插入和更新并找到 Dapper.Rainbow。我检查了一下,是
能够使用它来获取和插入如上所述的对象。我的
问题是当 Product 具有导航属性时,我无法执行
插入该字段。
...并提出替代方案,即 Dapper 库中已有的解决方案。我想我的问题应该更清楚,并明确询问整个Dapper library that is in github 中是否存在解决方案。因此,在库中进行了更多挖掘之后,我发现我的问题得到了支持。
Dapper.Contrib 的路径
我的项目和Rainbow 一切正常,直到我需要更多的东西。我得到了一些包含很多字段的表。如果我只是将我的对象提供给 Rainbow,那么它将对所有字段进行更新,这并不是很好。但这并没有让我迅速跳下船回到新罕布什尔州。所以在我实现自己的change tracking 之前,我不想重新发明轮子,特别是如果有人已经做得很好,我用谷歌搜索了found this SO thread。该线程证实了我的知识,Rainbow 不支持更改跟踪,但还有另一种野兽支持,它被称为 Dapper.Contrib。所以我开始尝试它。
于是我们又见面了
ProductCategory 类型的成员 Category 不能用作
参数值
我遇到了与Rainbow 相同的问题。 Contrib 不支持导航属性!?我开始觉得我在Dapper 上浪费了我的时间,它提供的性能,我非常追求,只是一厢情愿。直到……
WriteAttribute,来拯救...
此类位于 SqlMapperExtensions.cs 文件中,该文件包含在 Dapper.Contrib 项目中。我没有找到关于这个类的任何文档,也没有任何可以轻松找到它的 cmets 并对我大喊大叫并说hey I'm the one you're looking for。当我如上所述将 Rainbow 放在一边时,我偶然发现了这一点。
这个类的用法和我用IgnorePropertyAttribute做的一样,它是一个你可以用来装饰你的类的属性的属性。您应该使用此属性装饰您不希望包含在Dapper 创建的sql 中的任何属性。所以在我的例子中,让我告诉 Dapper 排除我需要这样做的 Category 字段:
public class Product {
public int Id {get;set;}
public string Name {get;set;}
[Write(false)] // tell Dapper to exclude this field from the sql
public ProductCategory Category {get;set;}
public int CategoryId {get;set;}
}
我快到了
请记住,我选择 Contrib 的原因是因为 change tracking 功能。 This SO thread,与我在上面给出的相同链接,指出要启动更改跟踪,您需要为您的课程提供一个接口并将其与Contrib 一起使用。所以对于我的示例类,我需要:
public interface IProduct {
int Id {get;set;}
string Name {get;set;}
ProductCategory Category {get;set;}
int Category {get;set;}
}
// and implement it on my Product class
public class Product : IProduct {
public int Id {get;set;}
public string Name {get;set;}
[Write(false)]
public ProductCategory Category {get;set;}
int Category {get;set;}
}
我以为就是这样,差不多!您可能会问,如果Dapper 根本不关心它,为什么我需要在我的界面中定义Category。事实上,这只会导致一个问题,一个我会解决的问题。
在我的特定场景中,有时我需要处理Category 字段,同时保持Product 对象的更改跟踪。为了保持跟踪能力,get 调用应该提供如下接口类型:
var product = connection.Get<IProduct>(id);
如果我不在我的界面中定义Category 字段,那么通过该调用我将不能够访问它。但如果我确实在我的界面中定义它,我会得到熟悉的错误
类型 {type} 的成员 {member} 不能用作参数
价值。
真的吗?请停下来。
判决
不用担心,因为这很容易通过装饰接口成员来解决,就像我们为类所做的那样。因此,使一切正常的最终配置应该是:
public interface IProduct {
// I will not discuss here what this attribute does
// as this is documented already in the github source.
// Just take note that this is needed,
// both here and in the implementing class.
[Key]
int Id {get;set;}
string Name {get;set;}
[Write(false)]
ProductCategory Category {get;set;}
int Category {get;set;}
}
// and implement it on my Product class
public class Product : IProduct {
[Key]
public int Id {get;set;}
public string Name {get;set;}
[Write(false)]
public ProductCategory Category {get;set;}
int Category {get;set;}
}
如果您更喜欢使用具有change tracking 功能的Contrib,则可以使用此方法。如果您想使用Rainbow 并且像我一样遇到导航属性问题,那么您可以play with my pull request。它与WriteAttribute 的工作方式相同,只是它与Rainbow 一起工作。
如果您不喜欢用属性装饰您的类,那么这两个扩展项目都不适合您。我知道还有另一个扩展项目可以让您进行某种流利类型的配置,但是 不 与Dapper 库一起使用(不包括作为核心部分)那是在github中。我的偏好是仅使用核心库,这引导我调查整个库,看看是否已经存在或者是否可以对其进行改进以满足我的需求。这就是我在此处为Rainbow 和Contrib 所做和解释的。
我希望这个贡献,我添加的非常简单的类,我展示的配置技巧,以及引导我的场景,将帮助将来希望使用 Dapper 的人,并且会有类似的设置我有。此外,这个答案将使开发人员更多地了解 Dapper 能做什么和不能做什么。这个很棒的工具叫做Dapperdeserves a better wiki,我希望这里的这个答案/文章能帮助到一点点。
**如果我在这里写的东西已经写在某个地方,我已经在等待答案的两周时间内没有发现,那么我很高兴有人将我链接到它。现在已经两周了,调查我的问题的 29 个人没有提出任何链接或解决方案,所以我认为我在这里分享的信息对 Dapper* 来说是新的:)
注意:我修改了我的问题标题,以便其他人可以看到他们问题的潜在解决方案。新标题是基于我获得的关于 Dapper 的新知识。