ORM 用于具有半灵活模式设计的数据库

发布于 2024-12-29 12:36:20 字数 662 浏览 1 评论 0 原文

我喜欢 Dapper、Massive、PetaPoco 等的“微”方法,并且我喜欢控制我们发送到数据库的 SQL,大多数时候它相对简单。我也喜欢使用 POCO,但是在处理稍微灵活的模式设计时,您经常会遇到麻烦:)

假设我们有一个 Person 实体,它始终具有以下属性。

  • Id
  • 姓名
  • 电子邮件
  • 电话

但在某些情况下可能会有其他属性,例如

  • SpecialPhoneNumber
  • VeryCustomValue

我真的很希望 POCO 具有我们知道将始终存在的常见属性。但可以在键/值集合中访问另一个。

最好的方法是什么?提到的“mirco-orm”是否支持这一点?我已经查看了所有这些,但没有发现任何迹象表明它们确实如此,但也许我错过了一些东西。

是否可以直接使用 SqlDataReader 来完成此操作?或者使用反射创建对象时读取数百行的性能会很差吗?提到的 orm 似乎都做得很好,我猜想在下面使用 DataReader。

希望您能提供帮助:)

编辑:我可能应该提到我们无法控制应用程序架构。这是一个 ERP 解决方案,允许个人客户定制他们的应用程序和底层数据库。在应用程序中添加字段会在数据库中添加列。坏我了!因为一开始就没有说清楚

I like the "micro" approach of Dapper, Massive, PetaPoco etc. and I like to have control over the SQL we send to the database, most of the time it's relatively simple. I also like working with POCO's however when dealing with a somewhat flexible schema design you often run into trouble :)

Let's say we have a Person entity, that ALWAYS have the following properties.

  • Id
  • Name
  • Email
  • Phone

But in some cases there might be additional properties like

  • SpecialPhoneNumber
  • VeryCustomValue

I would really like a POCO with the common properties that we know will always be there. But have the other accessible in a key/value collection.

What would be the best approach? And does any of the mentioned "mirco-orm's" support this? I have looked at them all but have not found any indication that they do, but maybe I'm missing something.

Would it be possible to do this directly with an SqlDataReader? or would the performance of reading hundreds of rows be bad when using reflection to create the objects? The mentioned orm's all seem to do pretty well and I guess the use a DataReader underneath.

Hope you can help :)

EDIT: I should probably mention that we have no control over the application architecture. This is an ERP solution that allows the individual customer to customize their application and the underlying database. Adding fields in the application adds columns in the database. Bad me! for not making that clear in the first place

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

只是在用心讲痛 2025-01-05 12:36:20

Massive 可以支持这一点,因为它将数据具体化为 ExpandoObject 的:

秘密武器是 ExpandoObject。所有进入和
Massive 产生的所有内容都是 Expando – 它可以让您
用它做任何你想做的事。 ExpandoObject 的核心是
只是一个 IDictionary<字符串,对象>

ExpandoObject 实现 IDictionaryIEnumerable>,这样您就可以按照您需要的任何方式枚举和测试成员。

Massive 的默认设置是发出 SELECT * 查询,因此 ExpandoObject 将包含表中的所有字段,甚至是您不知道的字段。

您可以从 Github 获取 Massive 的当前代码

Dapper 也可以选择动态对象,但与 Massive 不同的是它只能选择数据并且无法插入、更新或删除它。编辑:查看 Dapper 文档,它似乎可以执行修改,因为它可以执行任何 sql。有 有关使用 Dapper 执行插入的一些最新信息

Massive can support this, because it materializes data into ExpandoObject's:

The secret sauce is the ExpandoObject. Everything that goes in and
everything that comes out of Massive is an Expando – which allows you
to do whatever you want with it. At it’s core, an ExpandoObject is
just an IDictionary< string,object >

ExpandoObject implements IDictionary<string, Object> and IEnumerable<KeyValuePair<string, Object>>, so you can enumerate and test for members in any way you need to.

Massive's default is to issue a SELECT * query, so the ExpandoObject will contain all fields in the table, even those you do not know about.

You can get Massive's current code from Github.

Dapper can also select into dynamic objects, but unlike Massive it can only select data and cannot insert, update, or delete it. EDIT: Reviewing the Dapper docs, it appears it can perform modifications, as it can execute any sql. There is some more recent information about performing inserts with Dapper.

箹锭⒈辈孓 2025-01-05 12:36:20

在设计中使用每个类型继承表或扩展表以允许在实体上添加数据。

Use table per type inheritence or an extension table in your design to allow for the added data on an entity.

巡山小妖精 2025-01-05 12:36:20

MyBatis.NET(以前称为 iBatis.NET)是一个数据映射器工具,它有一个我认为非常有用的功能。如果您从未听说过它,它是一个 ORM 工具,允许您编写 SQL,创建域对象,并使用 XML 将数据库列映射到域对象属性。

这些结果映射之一可能如下所示:

<resultMap id="Contact" class="Contact" >
    <result property="ContactId" column="ContactId" />
    <result property="FirstName" column="FirstName" />
    <result property="MiddleInitial" column="MiddleInitial" />
    <result property="LastName" column="LastName" />
</resultMap>

其中有结果的 id、类别名(例如,映射到 Namespace.Folder.Contact)以及列到属性映射的列表。

您可能感兴趣的是能够扩展结果映射,就像从类继承一样。在您的情况下,您可能会:

<resultMap id="Person" class="Person" >
    <result property="Id" column="Id" />
    <result property="Name" column="Name" />
    <result property="Email" column="Email" />
    <result property="Phone" column="Phone" />
</resultMap>

对于您的其他情况:

<resultMap id="PersonExtended" extends="Person" class="Person">
    <!-- inherits all the "Person" result map properties -->
    <result property="SpecialPhoneNumber" column="SpecialPhoneNumber" />
    <result property="VeryCustomValue" column="VeryCustomValue" />
</resultMap>

然后您将有两个单独的查询,一个仅选择基本信息并映射到“Person”结果映射,另一个查询映射到“PersonExtended”包含更多列的结果图。

还支持选择字典并避免 N+1 选择。需要注意的是:我与 MyBatis 项目没有任何关系,我只是发现它非常灵活并且是一个非常可靠的数据映射器。我将它用于我的所有项目,主要是因为我编写了一个工具,只需将其指向数据库即可生成整个数据访问层。

设置它有点 PITA,但也许它对你有用!

MyBatis.NET (formerly iBatis.NET) is a data mapper tool that has a feature I find really useful. If you've never heard of it, it is an ORM tool that allows you to write the SQL, and you create the domain objects, and use XML to map the database columns to the domain object properties.

One of these result mappings might look like:

<resultMap id="Contact" class="Contact" >
    <result property="ContactId" column="ContactId" />
    <result property="FirstName" column="FirstName" />
    <result property="MiddleInitial" column="MiddleInitial" />
    <result property="LastName" column="LastName" />
</resultMap>

In there you have an id for the result, a class alias (which maps to Namespace.Folder.Contact, for example), and a list of column to property mappings.

Where you might have interest is in that there's an ability to extends result maps just as you would inherit from a class. In your situation, you might have:

<resultMap id="Person" class="Person" >
    <result property="Id" column="Id" />
    <result property="Name" column="Name" />
    <result property="Email" column="Email" />
    <result property="Phone" column="Phone" />
</resultMap>

And for your other situation:

<resultMap id="PersonExtended" extends="Person" class="Person">
    <!-- inherits all the "Person" result map properties -->
    <result property="SpecialPhoneNumber" column="SpecialPhoneNumber" />
    <result property="VeryCustomValue" column="VeryCustomValue" />
</resultMap>

And then you would have two separate queries, one that selects just the basic information and maps to the "Person" result map, and another query that maps to the "PersonExtended" result map that includes more columns.

There's also support for selecting to Dictionaries and avoiding N+1 selects. And just to note: I am no way affiliated with the MyBatis project, I've just found it really flexible and a pretty solid data mapper. I use it for all of my projects mostly because I wrote a tool that can generate my entire data access layer just by pointing it to a database.

Setting it up is a bit of PITA but maybe it could work for you!

痞味浪人 2025-01-05 12:36:20

你可以看一下nHibernate的动态映射。

http://ayende.com/blog/3942/nhibernate-mapping-dynamic-component

它允许您将此类扩展属性检索到通用Directory 中。因此,您的类具有此类通用包(字典)并动态扩展 XML 映射。

nHibernate 将为您完成剩下的工作。

You could take a look at nHibernate's dynamic mapping.

http://ayende.com/blog/3942/nhibernate-mapping-dynamic-component

It allows you to retrieve such extended properties into generic Directory<string,object>. Thus, you have your classes with such generic bags (dictionaries) and dynamically extend the XML mapping.

nHibernate will do the rest for you.

隐诗 2025-01-05 12:36:20

ID 姓名 电子邮件 电话
但在某些情况下可能还有其他属性,例如
特殊电话号码 VeryCustomValue

将架构师送回程序员学校 101。设计错误 - Phone、SpecialPhoneNumber 都不是 Person 的属性(无论如何它都不是 Person,而是“Entity”,因为它也可以是法人实体)。

它们是“接触点”或其他东西的列表。

也就是说,属性存储桶也可以在 ORM 中演示,但性能较差,但是,这就是 sql 数据库的工作方式。房地产桶表现不佳。

Id Name Email Phone
But in some cases there might be additional properties like
SpecialPhoneNumber VeryCustomValue

Send the architect back to programmer school 101. Design error - Phone, SpecialPhoneNumber are both NOT properties of Person (which is not Person anyway but "Entity" because it also can be a legal entity).

They are a list of "contactpoints" or something.

That said, property buckets can also be demonstrated in an ORM, with bad performance but hey, this is the way sql databases work. Bad performance for property buckets.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文