nhibernate - sproutcore:如何仅检索引用ID而不加载引用/关系?
我使用 nhibernate 驱动的 openrasta REST 解决方案作为前端 sproutcore 和后端。
在 sproutcore 中,引用实际上是 ID/guid。因此 Sproutcore 模型中的 Address 实体可以是:
// sproutcore code
App.Address = App.Base.extend(
street: SC.Record.attr( String, { defaultValue: "" }),
houseNumber: SC.Record.attr(String),
city: SC.Record.toOne('Funda.City') < /代码>
<代码>);
测试数据:
Funda.Address.FIXTURES = [
{ guid: "1",
street: "MyHomeStreet",
<代码>房屋号码:“34”,
<代码>城市:“6” }
]
这里您可以看到引用城市的值为 6。当您在程序中的某个时刻想要使用该引用时,可以通过以下方式完成: myAddress.Get("city").MyCityName
因此,Sproutcore 自动使用 REST Get 中提供的 ID,并检索所需的记录。如果该记录在客户端的本地内存中可用(之前已加载),则不会与服务器进行往返,否则将针对该 ID 进行 http get:“http://servername/city/6”。很不错。
Nhibernate(使用 Fluent-nhibernate 映射):
公共地址映射() { Schema(Config.ConfigElement("nh_default_schema", "Funda"));
Not.LazyLoad();
//Cache.ReadWrite();
Id(x => x.guid).Unique().GeneratedBy.Identity();
Table("Address");
Map(x => x.street);
Map(x => x.houseNumber);
References(x => x.city,
"cityID").LazyLoad().ForeignKey("fk_Address_cityID_City_guid");
}
这里我指定了外键,并将“cityID”映射到数据库表上。工作正常。 但是(这些是我向大师提出的问题):
- 您可以指定延迟加载/急切加载参考(城市)。当然,您不想急于加载所有参考资料。所以一般来说你与延迟加载有关。 但是,当 Openrast(或 WCF 或...)序列化此类对象时,它会迭代属性,这会导致属性的所有 get 被触发,从而导致所有引用被延迟加载。
因此,如果您的实体有 5 个引用,则将完成 1 个基础对象查询和 5 个引用查询。你可能最好立即加载然后...... 这太糟糕了……还是我错了?
- 当我展示 sproutcore 内部的模型如何工作时,我只想要引用的 ID。所以我不想急切加载,也不想延迟加载。 只是“从 ID = % 的地址获取 *”并将其映射到我的地址实体。 然后我还有令 Sproutcore 和我满意的参考文献 ID(不加载不需要的参考文献)。但是.... NHibernate 只能映射引用的 ID 吗? 我可以稍后指示 nHibernate 完全加载引用吗?
一种方法可能是(但不是一个好的方法)加载所有引用 EAGER (带有连接)(多么浪费资源..我知道)并在我的服务器端地址实体中:
// Note: NOT mapped as Datamember, is NOT serialized!
public virtual City city { get; set; }
Int32 _cityID;
[Datamember]
public virtual Int32 cityID
{
get
{
if (city != null)
return city .guid;
else
return _cityID;
}
set
{
if (city!= null && city.guid != value)
{
city= null;
_cityID = value;
}
else if (city == null)
{
_cityID = value;
}
}
}
因此,我获得了 Sproutcore 的 ID 属性,但缺点是所有引用都已加载。 对我来说更好的主意???
- nHibernate 到 linq
3a。我想在没有他们的参考资料的情况下获取我的地址(但最好有他们的 ID)
Dao myDao = new Dao(); 来自 myDao.All() 中的 p 选择p;
如果城市在我的映射中延迟加载,我如何在 linq 查询中指定我希望它也只包含我的城市 ID?
3b.
我想获取在 1 个查询中加载的城市地址:(映射为延迟加载)
Dao myDao = new Dao(); 来自 myDao.All() 中的 p 加入p.city??????? 选择p;
- 我的主要问题: 如前所述,通过延迟加载,序列化实体时所有引用都会延迟加载。我怎样才能防止这种情况,并且只以更有效的方式获取参考文献的 ID?
非常感谢您的阅读,希望您能帮助我和其他有同样问题的人。亲切的问候。
I use as a front-end sproutcore, and as back-end an nhibernate driven openrasta REST solution.
In sproutcore, references are actualy ID's / guid's. So an Address entity in the Sproutcore model could be:
// sproutcore code
App.Address = App.Base.extend(
street: SC.Record.attr(String, { defaultValue: "" }),
houseNumber: SC.Record.attr(String),
city: SC.Record.toOne('Funda.City')
);
with test data:
Funda.Address.FIXTURES = [
{ guid: "1",
street: "MyHomeStreet",
houseNumber: "34",
city: "6"
}
]
Here you see that the reference city has a value of 6. When, at some point in your program, you want to use that reference, it is done by:
myAddress.Get("city").MyCityName
So, Sproutcore automatically uses the supplied ID in a REST Get, and retrieves the needed record. If the record is available in de local memory of the client (previously loaded), then no round trip is made to the server, otherwise a http get is done for that ID : "http://servername/city/6". Very nice.
Nhibernate (mapped using fluent-nhibernate):
public AddressMap()
{
Schema(Config.ConfigElement("nh_default_schema", "Funda"));
Not.LazyLoad();
//Cache.ReadWrite();
Id(x => x.guid).Unique().GeneratedBy.Identity();
Table("Address");
Map(x => x.street);
Map(x => x.houseNumber);
References(x => x.city,
"cityID").LazyLoad().ForeignKey("fk_Address_cityID_City_guid");
}
Here i specified the foreign key, and to map "cityID" on the database table. It works ok.
BUT (and these are my questions for the guru's):
- You can specify to lazy load / eager load a reference (city). Off course you do not want to eager load all your references. SO generally your tied to lazy loading.
But when Openrast (or WCF or ...) serializes such an object, it iterates the properties, which causes all the get's of the properties to be fired, which causes all of the references to be lazy loaded.
SO if your entity has 5 references, 1 query for the base object, and 5 for the references will be done. You might better be off with eager loading then ....
This sucks... Or am i wrong?
- As i showed how the model inside sproutcore works, i only want the ID's of the references. So i Don't want eagerloading, and also not lazy loading.
just a "Get * from Address where ID = %" and get that mapped to my Address entity.
THen i also have the ID's of the references which pleases Sproutcore and me (no loading of unneeded references). But.... can NHibernate map the ID's of the references only?
And can i later indicate nHibernate to fully load the reference?
One approach could be (but is not a nice one) to load all reference EAGER (with join) (what a waste of resources.. i know) and in my Sever-side Address entity:
// Note: NOT mapped as Datamember, is NOT serialized!
public virtual City city { get; set; }
Int32 _cityID;
[Datamember]
public virtual Int32 cityID
{
get
{
if (city != null)
return city .guid;
else
return _cityID;
}
set
{
if (city!= null && city.guid != value)
{
city= null;
_cityID = value;
}
else if (city == null)
{
_cityID = value;
}
}
}
So i get my ID property for Sproutcore, but on the downside all references are loaded.
A better idea for me???
- nHibernate-to-linq
3a. I want to get my address without their references (but preferably with their id's)
Dao myDao = new Dao();
from p in myDao.All()
select p;
If cities are lazy loading in my mapping, how can i specify in the linq query that i want it also to include my city id only?
3b.
I want to get addresses with my cities loaded in 1 query: (which are mapped as lazyloaded)
Dao myDao = new Dao();
from p in myDao.All()
join p.city ???????
select p;
- My Main Question:
As argued earlier, with lazy loading, all references are lazy loaded when serializing entities. How can I prevent this, and only get ID's of references in a more efficient way?
Thank you very much for reading, and hopefully you can help me and others with the same questions. Kind regards.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
作为您写的注释,您执行此
myAddress.Get("city").MyCityName
,而它应该是
myAddress.get("city").get("MyCityName")
>或
myAddress.getPath("city.MyCityName")
有了这个,我认为您的问题是“如何在需要时才加载城市对象?”。
假设您正在使用数据源,当您请求城市对象时,您需要在数据源中进行管理。因此,在数据源中的
retrieveRecord
中,只需不触发请求,并使用适当的参数调用dataSourceDidComplete
(查看 datasource.js 文件),因此城市记录不会处于BUSY
状态。您基本上是在告诉存储记录已加载,但您传递了一个空哈希,因此该记录没有数据。当然,这样做的问题是在某些时候您需要检索记录。您可以定义一个像
App.WANTS_CITY
这样的全局变量,并在retrieveRecords
中仅在您需要城市时进行检索。您需要管理该触发器的值;状态图是执行此操作的好地方。您问题的另一部分是“如何一次加载一堆记录,而不是每个记录一个请求?”
请注意,数据源上有一个方法
retrieveRecords
。您可以为此方法定义自己的实现,这将允许您获取所需的任何记录 - 避免对 N 个子记录的 N 个请求 - 您可以在一个请求中完成所有这些操作。最后,就我个人而言,我倾向于使用
getAddress
等方法编写 API 层和
getCity
当我真正需要对象时, 并适当地调用我的 API。这种方法的一部分是我有一个非常轻的数据源——我基本上根据我的 API 层处理的内容放弃所有创建/更新/获取方法。我使用
pushRetrieve
和相关方法来更新商店。我这样做是因为商店以非常严格的方式使用数据源。我喜欢更多的灵活性;并非所有服务器 API 都以相同的方式工作。
as a note you wrote you do this
myAddress.Get("city").MyCityName
when it should be
myAddress.get("city").get("MyCityName")
or
myAddress.getPath("city.MyCityName")
With that out of the way, I think your question is "How do I not load the city object until I want to?".
Assuming you are using datasources, you need to manage in your datasource when you request the city object. So in
retrieveRecord
in your datasource simply don't fire the request, and calldataSourceDidComplete
with the appropriate arguments (look in the datasource.js file) so the city record is not in theBUSY
state. You are basically telling the store the record was loaded, but you pass an empty hash, so the record has no data.Of course the problem with this is at some point you will need to retrieve the record. You could define a global like
App.WANTS_CITY
and inretrieveRecords
only do the retrieve when you want the city. You need to manage the value of that trigger; statecharts are a good place to do this.Another part of your question was "How do I load a bunch of records at once, instead of one request for each record?"
Note on the datasource there is a method
retrieveRecords
. You can define your own implementation to this method, which would allow you to fetch any records you want -- that avoids N requests for N child records -- you can do them all in one request.Finally, personally, I tend to write an API layer with methods like
getAddress
and
getCity
and invoke my API appropriately, when I actually want the objects. Part of this approach is I have a very light datasource -- I basically bail out of all the create/update/fetch methods depending on what my API layer handles. I use the
pushRetrieve
and related methods to update the store.I do this because the store uses in datasources in a very rigid way. I like more flexibility; not all server APIs work in the same way.