Дискриминатор не используется в SQL для отображения один-ко-многим в ColdFusion ORM - PullRequest
2 голосов
/ 07 октября 2011

Допустим, у меня есть следующие объекты:

Магазин:

component
{
    property name="Id" fieldtype="id" generator="native";
    property name="Name";
    property name="Fruits" fieldtype="one-to-many" cfc="Fruit" inverse="true" cascade="all-delete-orphan";
    property name="Vegetables" fieldtype="one-to-many" cfc="Vegetable" inverse="true" cascade="all-delete-orphan";
}

Product.cfc

component table="Product" discriminatorcolumn="ProductType"
{
    property name="Id" fieldtype="id" generator="native";
    property name="Name";
    property name="Price";
    property name="Store" fieldtype="many-to-one" cfc="Store";
}

Fruit.cfc

component table="Product" extends="Product" discriminatorvalue="Fruit"
{
    property name="HasVitaminC" type="boolean";
}

Vegetable.cfc

component table="Product" extends="Product" discriminatorvalue="Vegetable"
{
    property name="IsGreen" type="boolean";
}

Другими словами, Store содержит набор Fruits и Vegetables, а Fruits и Vegetables расширяют базовый компонент Product. Я использую отображение таблицы на иерархию со столбцом дискриминатора для Products.

Проблема, с которой я сейчас сталкиваюсь, заключается в том, что я заполняю магазин и пытаюсь получить коллекцию Fruits или Vegetables:

var store = EntityLoadByPK("Store", 13);
var fruits = store.getFruits();

SQL, который он работает за кулисами, чтобы захватить фрукты:

select * from Product where store_id = 13;

Как видите, дискриминатор не используется, и я получаю фрукты и овощи. Когда я пытаюсь перебрать эту коллекцию, я получу сообщение об ошибке, потому что Vegetable - это несоответствие типов с Fruit.

Однако, если я попробую обратный путь, где я начну с Fruit и отфильтрую по Store:

var store = EntityLoadByPK("Store", 13);
var fruits = EntityLoad("Fruit", {store=store});

Будет запущен правильный SQL:

select * from Product where ProductType = 'Fruit' and store_id = 13;

У меня вопрос , что я делаю здесь неправильно, что позволяет ORM работать правильно, когда я фильтрую фрукты по магазинам, но не правильно, когда я пытаюсь получить коллекцию фруктов для магазина? Или я наткнулся на ошибку?

Редактировать: Вот файл CFM, который я выполняю для воспроизведения этого поведения:

<cfscript>
    ormReload();

    // create a new store
    store = EntityNew("Store");
    store.setName("Grocery Store");

    // create a new fruit and add it to the store
    fruit = EntityNew("Fruit");
    fruit.setName("Banana");
    fruit.setStore(store);
    store.addFruits(fruit);

    // create a new vegetable and add it to the store
    vegetable = EntityNew("Vegetable");
    vegetable.setName("Asparagus");
    vegetable.setStore(store);
    store.addVegetables(vegetable);

    // save the store
    EntitySave(store);

    // flush and clear out the session
    ormFlush();
    ormClearSession();

    // load the store and get its fruits collection, this will execute the
    // wrong SQL and return TWO items
    store = EntityLoad("Store")[1];
    fruits = store.getFruits();
    writedump(fruits);

    ormClearSession();

    // load the store and filter fruits by it, this will execute the
    // correct SQL and return only one item
    store = EntityLoad("Store")[1];
    fruits = EntityLoad("Fruit", {store=store});
    writedump(fruits);
</cfscript>

Ответы [ 3 ]

2 голосов
/ 07 октября 2011

Проблема в том, что у вас есть одна сопоставленная связь: связь «один к одному» между продуктом и магазином. Обе ассоциации «один ко многим» («овощи в магазине» и «фрукты в магазине») являются обратной ассоциацией одной ассоциации «продукт-магазин», которая недопустима.

Хотя я не уверен в лучшем решении. Более того, я знаю, что я могу сделать на Java, но не в Coldfusion. Посмотрите, как добавить предложение where или фильтр в отображение вашей коллекции (см. http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/annotations/Where.html и http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/annotations/Filter.html).

Или просто объедините один магазин товаров один ко многим и добавьте два пользовательских метода, фильтрующих коллекцию товаров.

0 голосов
/ 10 января 2012

У меня та же проблема.Я обошел это, добавив предложение WHERE на ОДНОЙ стороне моего отношения «один ко многим», так как мой целевой объект не знает другую сторону объединения.

Я согласен, что это ошибка,Кстати, какую версию CF вы используете?

Кроме того, вам повезло, определив ваши отношения как HBMXML и включив их?Это может выявить проблему реализации Adobe.http://help.adobe.com/en_US/ColdFusion/9.0/Developing/

0 голосов
/ 07 октября 2011

Я бы предложил использовать HQL в классе Store, чтобы сделать это примерно так:

function getFruits(){
  return ORMExecuteQuery( "
    from Product as p
    where p.class IN ( Fruit )
    and p.store = :Store ", 
    { Store=this } 
  );
}
...